diff options
-rw-r--r-- | hw/mips_jazz.c | 2 | ||||
-rw-r--r-- | hw/pci-hotplug.c | 4 | ||||
-rw-r--r-- | hw/pci.c | 11 | ||||
-rw-r--r-- | hw/pci.h | 1 | ||||
-rw-r--r-- | hw/ppc_prep.c | 2 | ||||
-rw-r--r-- | net.c | 901 | ||||
-rw-r--r-- | net.h | 12 | ||||
-rw-r--r-- | qemu-config.c | 16 | ||||
-rw-r--r-- | qemu-config.h | 1 | ||||
-rw-r--r-- | qemu-img.texi | 6 | ||||
-rw-r--r-- | qemu-option.c | 90 | ||||
-rw-r--r-- | qemu-option.h | 1 | ||||
-rw-r--r-- | qemu-options.hx | 10 | ||||
-rw-r--r-- | sdl.c | 18 | ||||
-rw-r--r-- | sysemu.h | 1 | ||||
-rw-r--r-- | vl.c | 19 |
16 files changed, 664 insertions, 431 deletions
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index 9578f28a4..3ff367d5c 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -209,7 +209,7 @@ void mips_jazz_init (ram_addr_t ram_size, for (n = 0; n < nb_nics; n++) { nd = &nd_table[n]; if (!nd->model) - nd->model = "dp83932"; + nd->model = qemu_strdup("dp83932"); if (strcmp(nd->model, "dp83932") == 0) { dp83932_init(nd, 0x80001000, 2, rc4030[4], rc4030_opaque, rc4030_dma_memory_rw); diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index 4a6b12c5b..615f3dd1b 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -47,10 +47,6 @@ static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, monitor_printf(mon, "Parameter addr not supported\n"); return NULL; } - - if (nd_table[ret].model && !pci_nic_supported(nd_table[ret].model)) - return NULL; - return pci_nic_init(&nd_table[ret], "rtl8139", devaddr); } @@ -936,17 +936,6 @@ static const char * const pci_nic_names[] = { NULL }; -int pci_nic_supported(const char *model) -{ - int i; - - for (i = 0; pci_nic_names[i]; i++) - if (strcmp(model, pci_nic_names[i]) == 0) - return 1; - - return 0; -} - /* Initialize a PCI NIC. */ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, const char *default_devaddr) @@ -306,7 +306,6 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, int devfn_min, int nirq); -int pci_nic_supported(const char *model); PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, const char *default_devaddr); PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 104874f2f..e674e454b 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -692,7 +692,7 @@ static void ppc_prep_init (ram_addr_t ram_size, nb_nics1 = NE2000_NB_MAX; for(i = 0; i < nb_nics1; i++) { if (nd_table[i].model == NULL) { - nd_table[i].model = "ne2k_isa"; + nd_table[i].model = qemu_strdup("ne2k_isa"); } if (strcmp(nd_table[i].model, "ne2k_isa") == 0) { isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); @@ -111,6 +111,7 @@ #include "audio/audio.h" #include "qemu_socket.h" #include "qemu-log.h" +#include "qemu-config.h" #include "slirp/libslirp.h" #include "qemu-queue.h" @@ -297,7 +298,7 @@ static char *assign_name(VLANClientState *vc1, const char *model) snprintf(buf, sizeof(buf), "%s.%d", model, id); - return strdup(buf); + return qemu_strdup(buf); } VLANClientState *qemu_new_vlan_client(VLANState *vlan, @@ -311,9 +312,9 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, { VLANClientState *vc, **pvc; vc = qemu_mallocz(sizeof(VLANClientState)); - vc->model = strdup(model); + vc->model = qemu_strdup(model); if (name) - vc->name = strdup(name); + vc->name = qemu_strdup(name); else vc->name = assign_name(vc, model); vc->can_receive = can_receive; @@ -341,8 +342,8 @@ void qemu_del_vlan_client(VLANClientState *vc) if (vc->cleanup) { vc->cleanup(vc); } - free(vc->name); - free(vc->model); + qemu_free(vc->name); + qemu_free(vc->model); qemu_free(vc); break; } else @@ -660,21 +661,6 @@ qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt) return qemu_sendv_packet_async(vc, iov, iovcnt, NULL); } -static void config_error(Monitor *mon, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - if (mon) { - monitor_vprintf(mon, fmt, ap); - } else { - fprintf(stderr, "qemu: "); - vfprintf(stderr, fmt, ap); - exit(1); - } - va_end(ap); -} - #if defined(CONFIG_SLIRP) /* slirp network adapter */ @@ -704,16 +690,16 @@ const char *legacy_bootp_filename; static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks = QTAILQ_HEAD_INITIALIZER(slirp_stacks); -static void slirp_hostfwd(SlirpState *s, Monitor *mon, const char *redir_str, +static int slirp_hostfwd(SlirpState *s, const char *redir_str, + int legacy_format); +static int slirp_guestfwd(SlirpState *s, const char *config_str, int legacy_format); -static void slirp_guestfwd(SlirpState *s, Monitor *mon, const char *config_str, - int legacy_format); #ifndef _WIN32 static const char *legacy_smb_export; -static void slirp_smb(SlirpState *s, Monitor *mon, const char *exported_dir, - struct in_addr vserver_addr); +static int slirp_smb(SlirpState *s, const char *exported_dir, + struct in_addr vserver_addr); static void slirp_smb_cleanup(SlirpState *s); #else static inline void slirp_smb_cleanup(SlirpState *s) { } @@ -759,7 +745,7 @@ static void net_slirp_cleanup(VLANClientState *vc) qemu_free(s); } -static int net_slirp_init(Monitor *mon, VLANState *vlan, const char *model, +static int net_slirp_init(VLANState *vlan, const char *model, const char *name, int restricted, const char *vnetwork, const char *vhost, const char *vhostname, const char *tftp_export, @@ -781,6 +767,7 @@ static int net_slirp_init(Monitor *mon, VLANState *vlan, const char *model, uint32_t addr; int shift; char *end; + struct slirp_config_str *config; if (!tftp_export) { tftp_export = legacy_tftp_prefix; @@ -865,25 +852,24 @@ static int net_slirp_init(Monitor *mon, VLANState *vlan, const char *model, tftp_export, bootfile, dhcp, dns, s); QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); - while (slirp_configs) { - struct slirp_config_str *config = slirp_configs; - + for (config = slirp_configs; config; config = config->next) { if (config->flags & SLIRP_CFG_HOSTFWD) { - slirp_hostfwd(s, mon, config->str, - config->flags & SLIRP_CFG_LEGACY); + if (slirp_hostfwd(s, config->str, + config->flags & SLIRP_CFG_LEGACY) < 0) + return -1; } else { - slirp_guestfwd(s, mon, config->str, - config->flags & SLIRP_CFG_LEGACY); + if (slirp_guestfwd(s, config->str, + config->flags & SLIRP_CFG_LEGACY) < 0) + return -1; } - slirp_configs = config->next; - qemu_free(config); } #ifndef _WIN32 if (!smb_export) { smb_export = legacy_smb_export; } if (smb_export) { - slirp_smb(s, mon, smb_export, smbsrv); + if (slirp_smb(s, smb_export, smbsrv) < 0) + return -1; } #endif @@ -976,8 +962,8 @@ void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict) monitor_printf(mon, "invalid format\n"); } -static void slirp_hostfwd(SlirpState *s, Monitor *mon, const char *redir_str, - int legacy_format) +static int slirp_hostfwd(SlirpState *s, const char *redir_str, + int legacy_format) { struct in_addr host_addr = { .s_addr = INADDR_ANY }; struct in_addr guest_addr = { .s_addr = 0 }; @@ -1030,13 +1016,15 @@ static void slirp_hostfwd(SlirpState *s, Monitor *mon, const char *redir_str, if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr, guest_port) < 0) { - config_error(mon, "could not set up host forwarding rule '%s'\n", - redir_str); + qemu_error("could not set up host forwarding rule '%s'\n", + redir_str); + return -1; } - return; + return 0; fail_syntax: - config_error(mon, "invalid host forwarding rule '%s'\n", redir_str); + qemu_error("invalid host forwarding rule '%s'\n", redir_str); + return -1; } void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict) @@ -1055,12 +1043,12 @@ void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict) redir_str = arg1; } if (s) { - slirp_hostfwd(s, mon, redir_str, 0); + slirp_hostfwd(s, redir_str, 0); } } -void net_slirp_redir(const char *redir_str) +int net_slirp_redir(const char *redir_str) { struct slirp_config_str *config; @@ -1070,10 +1058,10 @@ void net_slirp_redir(const char *redir_str) config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY; config->next = slirp_configs; slirp_configs = config; - return; + return 0; } - slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), NULL, redir_str, 1); + return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1); } #ifndef _WIN32 @@ -1090,8 +1078,8 @@ static void slirp_smb_cleanup(SlirpState *s) } } -static void slirp_smb(SlirpState* s, Monitor *mon, const char *exported_dir, - struct in_addr vserver_addr) +static int slirp_smb(SlirpState* s, const char *exported_dir, + struct in_addr vserver_addr) { static int instance; char smb_conf[128]; @@ -1101,18 +1089,17 @@ static void slirp_smb(SlirpState* s, Monitor *mon, 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) { - config_error(mon, "could not create samba server dir '%s'\n", - s->smb_dir); - return; + qemu_error("could not create samba server dir '%s'\n", s->smb_dir); + return -1; } snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf"); f = fopen(smb_conf, "w"); if (!f) { slirp_smb_cleanup(s); - config_error(mon, "could not create samba server " - "configuration file '%s'\n", smb_conf); - return; + qemu_error("could not create samba server configuration file '%s'\n", + smb_conf); + return -1; } fprintf(f, "[global]\n" @@ -1142,24 +1129,27 @@ static void slirp_smb(SlirpState* s, Monitor *mon, const char *exported_dir, if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) { slirp_smb_cleanup(s); - config_error(mon, "conflicting/invalid smbserver address\n"); + qemu_error("conflicting/invalid smbserver address\n"); + return -1; } + return 0; } /* automatic user mode samba server configuration (legacy interface) */ -void net_slirp_smb(const char *exported_dir) +int net_slirp_smb(const char *exported_dir) { struct in_addr vserver_addr = { .s_addr = 0 }; if (legacy_smb_export) { fprintf(stderr, "-smb given twice\n"); - exit(1); + return -1; } legacy_smb_export = exported_dir; if (!QTAILQ_EMPTY(&slirp_stacks)) { - slirp_smb(QTAILQ_FIRST(&slirp_stacks), NULL, exported_dir, - vserver_addr); + return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir, + vserver_addr); } + return 0; } #endif /* !defined(_WIN32) */ @@ -1183,8 +1173,8 @@ static void guestfwd_read(void *opaque, const uint8_t *buf, int size) slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size); } -static void slirp_guestfwd(SlirpState *s, Monitor *mon, const char *config_str, - int legacy_format) +static int slirp_guestfwd(SlirpState *s, const char *config_str, + int legacy_format) { struct in_addr server = { .s_addr = 0 }; struct GuestFwd *fwd; @@ -1224,17 +1214,16 @@ static void slirp_guestfwd(SlirpState *s, Monitor *mon, const char *config_str, snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port); fwd->hd = qemu_chr_open(buf, p, NULL); if (!fwd->hd) { - config_error(mon, "could not open guest forwarding device '%s'\n", - buf); + qemu_error("could not open guest forwarding device '%s'\n", buf); qemu_free(fwd); - return; + return -1; } if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) { - config_error(mon, "conflicting/invalid host:port in guest forwarding " - "rule '%s'\n", config_str); + qemu_error("conflicting/invalid host:port in guest forwarding " + "rule '%s'\n", config_str); qemu_free(fwd); - return; + return -1; } fwd->server = server; fwd->port = port; @@ -1242,10 +1231,11 @@ static void slirp_guestfwd(SlirpState *s, Monitor *mon, const char *config_str, qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, NULL, fwd); - return; + return 0; fail_syntax: - config_error(mon, "invalid guest forwarding rule '%s'\n", config_str); + qemu_error("invalid guest forwarding rule '%s'\n", config_str); + return -1; } void do_info_usernet(Monitor *mon) @@ -1460,29 +1450,25 @@ static void tap_send(void *opaque) */ #define TAP_DEFAULT_SNDBUF 1024*1024 -static void tap_set_sndbuf(TAPState *s, const char *sndbuf_str, Monitor *mon) +static int tap_set_sndbuf(TAPState *s, QemuOpts *opts) { - int sndbuf = TAP_DEFAULT_SNDBUF; - - if (sndbuf_str) { - sndbuf = atoi(sndbuf_str); - } + int sndbuf; + sndbuf = qemu_opt_get_size(opts, "sndbuf", TAP_DEFAULT_SNDBUF); if (!sndbuf) { sndbuf = INT_MAX; } - if (ioctl(s->fd, TUNSETSNDBUF, &sndbuf) == -1 && sndbuf_str) { - config_error(mon, "TUNSETSNDBUF ioctl failed: %s\n", - strerror(errno)); + if (ioctl(s->fd, TUNSETSNDBUF, &sndbuf) == -1 && qemu_opt_get(opts, "sndbuf")) { + qemu_error("TUNSETSNDBUF ioctl failed: %s\n", strerror(errno)); + return -1; } + return 0; } #else -static void tap_set_sndbuf(TAPState *s, const char *sndbuf_str, Monitor *mon) +static int tap_set_sndbuf(TAPState *s, QemuOpts *opts) { - if (sndbuf_str) { - config_error(mon, "No '-net tap,sndbuf=<nbytes>' support available\n"); - } + return 0; } #endif /* TUNSETSNDBUF */ @@ -2298,8 +2284,8 @@ static int net_socket_listen_init(VLANState *vlan, return -1; } s->vlan = vlan; - s->model = strdup(model); - s->name = name ? strdup(name) : NULL; + s->model = qemu_strdup(model); + s->name = name ? qemu_strdup(name) : NULL; s->fd = fd; qemu_set_fd_handler(fd, net_socket_accept, NULL, s); return 0; @@ -2449,7 +2435,7 @@ static void net_dump_cleanup(VLANClientState *vc) qemu_free(s); } -static int net_dump_init(Monitor *mon, VLANState *vlan, const char *device, +static int net_dump_init(VLANState *vlan, const char *device, const char *name, const char *filename, int len) { struct pcap_file_hdr hdr; @@ -2459,7 +2445,7 @@ static int net_dump_init(Monitor *mon, VLANState *vlan, const char *device, s->fd = open(filename, O_CREAT | O_WRONLY | O_BINARY, 0644); if (s->fd < 0) { - config_error(mon, "-net dump: can't open %s\n", filename); + qemu_error("-net dump: can't open %s\n", filename); return -1; } @@ -2474,7 +2460,7 @@ static int net_dump_init(Monitor *mon, VLANState *vlan, const char *device, hdr.linktype = 1; if (write(s->fd, &hdr, sizeof(hdr)) < sizeof(hdr)) { - config_error(mon, "-net dump write error: %s\n", strerror(errno)); + qemu_error("-net dump write error: %s\n", strerror(errno)); close(s->fd); qemu_free(s); return -1; @@ -2551,7 +2537,7 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models, int i; if (!nd->model) - nd->model = strdup(default_model); + nd->model = qemu_strdup(default_model); for (i = 0 ; models[i]; i++) { if (strcmp(nd->model, models[i]) == 0) @@ -2569,7 +2555,7 @@ static int net_handle_fd_param(Monitor *mon, const char *param) fd = monitor_get_fd(mon, param); if (fd == -1) { - config_error(mon, "No file descriptor named %s found", param); + qemu_error("No file descriptor named %s found", param); return -1; } @@ -2579,6 +2565,442 @@ static int net_handle_fd_param(Monitor *mon, const char *param) } } +static int net_init_nic(QemuOpts *opts, Monitor *mon) +{ + int idx; + NICInfo *nd; + + idx = nic_get_free_idx(); + if (idx == -1 || nb_nics >= MAX_NICS) { + qemu_error("Too Many NICs\n"); + return -1; + } + + nd = &nd_table[idx]; + + memset(nd, 0, sizeof(*nd)); + + nd->vlan = qemu_find_vlan(qemu_opt_get_number(opts, "vlan", 0), 1); + + if (qemu_opts_id(opts)) { + nd->id = qemu_strdup(qemu_opts_id(opts)); + } + if (qemu_opt_get(opts, "name")) { + nd->name = qemu_strdup(qemu_opt_get(opts, "name")); + } + if (qemu_opt_get(opts, "model")) { + nd->model = qemu_strdup(qemu_opt_get(opts, "model")); + } + if (qemu_opt_get(opts, "addr")) { + nd->devaddr = qemu_strdup(qemu_opt_get(opts, "addr")); + } + + nd->macaddr[0] = 0x52; + nd->macaddr[1] = 0x54; + nd->macaddr[2] = 0x00; + nd->macaddr[3] = 0x12; + nd->macaddr[4] = 0x34; + nd->macaddr[5] = 0x56 + idx; + + if (qemu_opt_get(opts, "macaddr") && + parse_macaddr(nd->macaddr, qemu_opt_get(opts, "macaddr")) < 0) { + qemu_error("invalid syntax for ethernet address\n"); + return -1; + } + + nd->nvectors = qemu_opt_get_number(opts, "vectors", NIC_NVECTORS_UNSPECIFIED); + if (nd->nvectors != NIC_NVECTORS_UNSPECIFIED && + (nd->nvectors < 0 || nd->nvectors > 0x7ffffff)) { + qemu_error("invalid # of vectors: %d\n", nd->nvectors); + return -1; + } + + nd->used = 1; + nd->vlan->nb_guest_devs++; + nb_nics++; + + return idx; +} + +static int net_init_slirp_configs(const char *name, const char *value, void *opaque) +{ + struct slirp_config_str *config; + + if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) { + return 0; + } + + config = qemu_mallocz(sizeof(*config)); + + pstrcpy(config->str, sizeof(config->str), value); + + if (!strcmp(name, "hostfwd")) { + config->flags = SLIRP_CFG_HOSTFWD; + } + + config->next = slirp_configs; + slirp_configs = config; + + return 0; +} + +static int net_init_slirp(QemuOpts *opts, Monitor *mon) +{ + VLANState *vlan; + struct slirp_config_str *config; + const char *name; + const char *vhost; + const char *vhostname; + const char *vdhcp_start; + const char *vnamesrv; + const char *tftp_export; + const char *bootfile; + const char *smb_export; + const char *vsmbsrv; + char *vnet = NULL; + int restricted = 0; + int ret; + + vlan = qemu_find_vlan(qemu_opt_get_number(opts, "vlan", 0), 1); + + name = qemu_opt_get(opts, "name"); + + vhost = qemu_opt_get(opts, "host"); + vhostname = qemu_opt_get(opts, "hostname"); + vdhcp_start = qemu_opt_get(opts, "dhcpstart"); + vnamesrv = qemu_opt_get(opts, "dns"); + tftp_export = qemu_opt_get(opts, "tftp"); + bootfile = qemu_opt_get(opts, "bootfile"); + smb_export = qemu_opt_get(opts, "smb"); + vsmbsrv = qemu_opt_get(opts, "smbserver"); + + if (qemu_opt_get(opts, "ip")) { + const char *ip = qemu_opt_get(opts, "ip"); + int l = strlen(ip) + strlen("/24") + 1; + + vnet = qemu_malloc(l); + + /* emulate legacy ip= parameter */ + pstrcpy(vnet, l, ip); + pstrcat(vnet, l, "/24"); + } + + if (qemu_opt_get(opts, "net")) { + if (vnet) { + qemu_free(vnet); + } + vnet = qemu_strdup(qemu_opt_get(opts, "net")); + } + + if (qemu_opt_get(opts, "restrict") && + qemu_opt_get(opts, "restrict")[0] == 'y') { + restricted = 1; + } + + qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0); + + ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost, + vhostname, tftp_export, bootfile, vdhcp_start, + vnamesrv, smb_export, vsmbsrv); + + while (slirp_configs) { + config = slirp_configs; + slirp_configs = config->next; + qemu_free(config); + } + + if (ret != -1) { + vlan->nb_host_devs++; + } + + qemu_free(vnet); + + return ret; +} + +#ifdef _WIN32 +static int net_init_tap_win32(QemuOpts *opts, Monitor *mon) +{ + VLANState *vlan; + const char *name; + const char *ifname; + + vlan = qemu_find_vlan(qemu_opt_get_number(opts, "vlan", 0), 1); + + name = qemu_opt_get(opts, "name"); + ifname = qemu_opt_get(opts, "ifname"); + + if (!ifname) { + qemu_error("tap: no interface name\n"); + return -1; + } + + if (tap_win32_init(vlan, "tap", name, ifname) == -1) { + return -1; + } + + vlan->nb_host_devs++; + + return 0; +} +#elif !defined(_AIX) +static int net_init_tap(QemuOpts *opts, Monitor *mon) +{ + VLANState *vlan; + const char *name; + TAPState *s; + + vlan = qemu_find_vlan(qemu_opt_get_number(opts, "vlan", 0), 1); + + name = qemu_opt_get(opts, "name"); + + if (qemu_opt_get(opts, "fd")) { + int fd; + + if (qemu_opt_get(opts, "ifname") || + qemu_opt_get(opts, "script") || + qemu_opt_get(opts, "downscript")) { + qemu_error("ifname=, script= and downscript= is invalid with fd=\n"); + return -1; + } + + fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd")); + if (fd == -1) { + return -1; + } + + fcntl(fd, F_SETFL, O_NONBLOCK); + + s = net_tap_fd_init(vlan, "tap", name, fd, tap_probe_vnet_hdr(fd)); + if (!s) { + close(fd); + } + } else { + const char *ifname, *script, *downscript; + + ifname = qemu_opt_get(opts, "ifname"); + script = qemu_opt_get(opts, "script"); + downscript = qemu_opt_get(opts, "downscript"); + + if (!script) { + script = DEFAULT_NETWORK_SCRIPT; + } + if (!downscript) { + downscript = DEFAULT_NETWORK_DOWN_SCRIPT; + } + + s = net_tap_init(vlan, "tap", name, ifname, script, downscript); + } + + if (!s) { + return -1; + } + + if (tap_set_sndbuf(s, opts) < 0) { + return -1; + } + + vlan->nb_host_devs++; + + return 0; +} +#endif + +#define NET_COMMON_PARAMS_DESC \ + { \ + .name = "type", \ + .type = QEMU_OPT_STRING, \ + .help = "net client type (nic, tap etc.)", \ + }, { \ + .name = "vlan", \ + .type = QEMU_OPT_NUMBER, \ + .help = "vlan number", \ + }, { \ + .name = "name", \ + .type = QEMU_OPT_STRING, \ + .help = "identifier for monitor commands", \ + } + +typedef int (*net_client_init_func)(QemuOpts *opts, Monitor *mon); + +/* magic number, but compiler will warn if too small */ +#define NET_MAX_DESC 20 + +static struct { + const char *type; + net_client_init_func init; + QemuOptDesc desc[NET_MAX_DESC]; +} net_client_types[] = { + { + .type = "none", + .desc = { + NET_COMMON_PARAMS_DESC, + { /* end of list */ } + }, + }, { + .type = "nic", + .init = net_init_nic, + .desc = { + NET_COMMON_PARAMS_DESC, + { + .name = "macaddr", + .type = QEMU_OPT_STRING, + .help = "MAC address", + }, { + .name = "model", + .type = QEMU_OPT_STRING, + .help = "device model (e1000, rtl8139, virtio etc.)", + }, { + .name = "addr", + .type = QEMU_OPT_STRING, + .help = "PCI device address", + }, { + .name = "vectors", + .type = QEMU_OPT_NUMBER, + .help = "number of MSI-x vectors, 0 to disable MSI-X", + }, + { /* end of list */ } + }, +#ifdef CONFIG_SLIRP + }, { + .type = "user", + .init = net_init_slirp, + .desc = { + NET_COMMON_PARAMS_DESC, + { + .name = "hostname", + .type = QEMU_OPT_STRING, + .help = "client hostname reported by the builtin DHCP server", + }, { + .name = "restrict", + .type = QEMU_OPT_STRING, + .help = "isolate the guest from the host (y|yes|n|no)", + }, { + .name = "ip", + .type = QEMU_OPT_STRING, + .help = "legacy parameter, use net= instead", + }, { + .name = "net", + .type = QEMU_OPT_STRING, + .help = "IP address and optional netmask", + }, { + .name = "host", + .type = QEMU_OPT_STRING, + .help = "guest-visible address of the host", + }, { + .name = "tftp", + .type = QEMU_OPT_STRING, + .help = "root directory of the built-in TFTP server", + }, { + .name = "bootfile", + .type = QEMU_OPT_STRING, + .help = "BOOTP filename, for use with tftp=", + }, { + .name = "dhcpstart", + .type = QEMU_OPT_STRING, + .help = "the first of the 16 IPs the built-in DHCP server can assign", + }, { + .name = "dns", + .type = QEMU_OPT_STRING, + .help = "guest-visible address of the virtual nameserver", + }, { + .name = "smb", + .type = QEMU_OPT_STRING, + .help = "root directory of the built-in SMB server", + }, { + .name = "smbserver", + .type = QEMU_OPT_STRING, + .help = "IP address of the built-in SMB server", + }, { + .name = "hostfwd", + .type = QEMU_OPT_STRING, + .help = "guest port number to forward incoming TCP or UDP connections", + }, { + .name = "guestfwd", + .type = QEMU_OPT_STRING, + .help = "IP address and port to forward guest TCP connections", + }, + { /* end of list */ } + }, +#endif +#ifdef _WIN32 + }, { + .type = "tap", + .init = net_init_tap_win32, + .desc = { + NET_COMMON_PARAMS_DESC, + { + .name = "ifname", + .type = QEMU_OPT_STRING, + .help = "interface name", + }, + { /* end of list */ } + }, +#elif !defined(_AIX) + }, { + .type = "tap", + .init = net_init_tap, + .desc = { + NET_COMMON_PARAMS_DESC, + { + .name = "fd", + .type = QEMU_OPT_STRING, + .help = "file descriptor of an already opened tap", + }, { + .name = "ifname", + .type = QEMU_OPT_STRING, + .help = "interface name", + }, { + .name = "script", + .type = QEMU_OPT_STRING, + .help = "script to initialize the interface", + }, { + .name = "downscript", + .type = QEMU_OPT_STRING, + .help = "script to shut down the interface", +#ifdef TUNSETSNDBUF + }, { + .name = "sndbuf", + .type = QEMU_OPT_SIZE, + .help = "send buffer limit" +#endif + }, + { /* end of list */ } + }, +#endif + }, + { /* end of list */ } +}; + +static int net_client_init_from_opts(Monitor *mon, QemuOpts *opts) +{ + const char *type; + int i; + + type = qemu_opt_get(opts, "type"); + if (!type) { + qemu_error("No type specified for -net\n"); + return -1; + } + + for (i = 0; net_client_types[i].type != NULL; i++) { + if (!strcmp(net_client_types[i].type, type)) { + if (qemu_opts_validate(opts, &net_client_types[i].desc[0]) == -1) { + return -1; + } + + if (net_client_types[i].init) { + return net_client_types[i].init(opts, NULL); + } else { + return 0; + } + } + } + + qemu_error("Invalid -net type '%s'\n", type); + return -1; +} + int net_client_init(Monitor *mon, const char *device, const char *p) { char buf[1024]; @@ -2586,6 +3008,22 @@ int net_client_init(Monitor *mon, const char *device, const char *p) VLANState *vlan; char *name = NULL; + if (!strcmp(device, "none") || + !strcmp(device, "nic") || + !strcmp(device, "user") || + !strcmp(device, "tap")) { + QemuOpts *opts; + + opts = qemu_opts_parse(&qemu_net_opts, p, NULL); + if (!opts) { + return -1; + } + + qemu_opt_set(opts, "type", device); + + return net_client_init_from_opts(mon, opts); + } + vlan_id = 0; if (get_param_value(buf, sizeof(buf), "vlan", p)) { vlan_id = strtol(buf, NULL, 0); @@ -2595,184 +3033,9 @@ int net_client_init(Monitor *mon, const char *device, const char *p) if (get_param_value(buf, sizeof(buf), "name", p)) { name = qemu_strdup(buf); } - if (!strcmp(device, "nic")) { - static const char * const nic_params[] = { - "vlan", "name", "macaddr", "model", "addr", "id", "vectors", NULL - }; - NICInfo *nd; - uint8_t *macaddr; - int idx = nic_get_free_idx(); - if (check_params(buf, sizeof(buf), nic_params, p) < 0) { - config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p); - ret = -1; - goto out; - } - if (idx == -1 || nb_nics >= MAX_NICS) { - config_error(mon, "Too Many NICs\n"); - ret = -1; - goto out; - } - nd = &nd_table[idx]; - macaddr = nd->macaddr; - macaddr[0] = 0x52; - macaddr[1] = 0x54; - macaddr[2] = 0x00; - macaddr[3] = 0x12; - macaddr[4] = 0x34; - macaddr[5] = 0x56 + idx; - - if (get_param_value(buf, sizeof(buf), "macaddr", p)) { - if (parse_macaddr(macaddr, buf) < 0) { - config_error(mon, "invalid syntax for ethernet address\n"); - ret = -1; - goto out; - } - } - if (get_param_value(buf, sizeof(buf), "model", p)) { - nd->model = strdup(buf); - } - if (get_param_value(buf, sizeof(buf), "addr", p)) { - nd->devaddr = strdup(buf); - } - if (get_param_value(buf, sizeof(buf), "id", p)) { - nd->id = strdup(buf); - } - nd->nvectors = NIC_NVECTORS_UNSPECIFIED; - if (get_param_value(buf, sizeof(buf), "vectors", p)) { - char *endptr; - long vectors = strtol(buf, &endptr, 0); - if (*endptr) { - config_error(mon, "invalid syntax for # of vectors\n"); - ret = -1; - goto out; - } - if (vectors < 0 || vectors > 0x7ffffff) { - config_error(mon, "invalid # of vectors\n"); - ret = -1; - goto out; - } - nd->nvectors = vectors; - } - nd->vlan = vlan; - nd->name = name; - nd->used = 1; - name = NULL; - nb_nics++; - vlan->nb_guest_devs++; - ret = idx; - } else - if (!strcmp(device, "none")) { - if (*p != '\0') { - config_error(mon, "'none' takes no parameters\n"); - ret = -1; - goto out; - } - /* does nothing. It is needed to signal that no network cards - are wanted */ - ret = 0; - } else #ifdef CONFIG_SLIRP - if (!strcmp(device, "user")) { - static const char * const slirp_params[] = { - "vlan", "name", "hostname", "restrict", "ip", "net", "host", - "tftp", "bootfile", "dhcpstart", "dns", "smb", "smbserver", - "hostfwd", "guestfwd", NULL - }; - struct slirp_config_str *config; - int restricted = 0; - char *vnet = NULL; - char *vhost = NULL; - char *vhostname = NULL; - char *tftp_export = NULL; - char *bootfile = NULL; - char *vdhcp_start = NULL; - char *vnamesrv = NULL; - char *smb_export = NULL; - char *vsmbsrv = NULL; - const char *q; - - if (check_params(buf, sizeof(buf), slirp_params, p) < 0) { - config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p); - ret = -1; - goto out; - } - if (get_param_value(buf, sizeof(buf), "ip", p)) { - int vnet_buflen = strlen(buf) + strlen("/24") + 1; - /* emulate legacy parameter */ - vnet = qemu_malloc(vnet_buflen); - pstrcpy(vnet, vnet_buflen, buf); - pstrcat(vnet, vnet_buflen, "/24"); - } - if (get_param_value(buf, sizeof(buf), "net", p)) { - vnet = qemu_strdup(buf); - } - if (get_param_value(buf, sizeof(buf), "host", p)) { - vhost = qemu_strdup(buf); - } - if (get_param_value(buf, sizeof(buf), "hostname", p)) { - vhostname = qemu_strdup(buf); - } - if (get_param_value(buf, sizeof(buf), "restrict", p)) { - restricted = (buf[0] == 'y') ? 1 : 0; - } - if (get_param_value(buf, sizeof(buf), "dhcpstart", p)) { - vdhcp_start = qemu_strdup(buf); - } - if (get_param_value(buf, sizeof(buf), "dns", p)) { - vnamesrv = qemu_strdup(buf); - } - if (get_param_value(buf, sizeof(buf), "tftp", p)) { - tftp_export = qemu_strdup(buf); - } - if (get_param_value(buf, sizeof(buf), "bootfile", p)) { - bootfile = qemu_strdup(buf); - } - if (get_param_value(buf, sizeof(buf), "smb", p)) { - smb_export = qemu_strdup(buf); - if (get_param_value(buf, sizeof(buf), "smbserver", p)) { - vsmbsrv = qemu_strdup(buf); - } - } - q = p; - while (1) { - config = qemu_malloc(sizeof(*config)); - if (!get_next_param_value(config->str, sizeof(config->str), - "hostfwd", &q)) { - break; - } - config->flags = SLIRP_CFG_HOSTFWD; - config->next = slirp_configs; - slirp_configs = config; - config = NULL; - } - q = p; - while (1) { - config = qemu_malloc(sizeof(*config)); - if (!get_next_param_value(config->str, sizeof(config->str), - "guestfwd", &q)) { - break; - } - config->flags = 0; - config->next = slirp_configs; - slirp_configs = config; - config = NULL; - } - qemu_free(config); - vlan->nb_host_devs++; - ret = net_slirp_init(mon, vlan, device, name, restricted, vnet, vhost, - vhostname, tftp_export, bootfile, vdhcp_start, - vnamesrv, smb_export, vsmbsrv); - qemu_free(vnet); - qemu_free(vhost); - qemu_free(vhostname); - qemu_free(tftp_export); - qemu_free(bootfile); - qemu_free(vdhcp_start); - qemu_free(vnamesrv); - qemu_free(smb_export); - qemu_free(vsmbsrv); - } else if (!strcmp(device, "channel")) { + if (!strcmp(device, "channel")) { if (QTAILQ_EMPTY(&slirp_stacks)) { struct slirp_config_str *config; @@ -2781,87 +3044,9 @@ int net_client_init(Monitor *mon, const char *device, const char *p) config->flags = SLIRP_CFG_LEGACY; config->next = slirp_configs; slirp_configs = config; - } else { - slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), mon, p, 1); - } - ret = 0; - } else -#endif -#ifdef _WIN32 - if (!strcmp(device, "tap")) { - static const char * const tap_params[] = { - "vlan", "name", "ifname", NULL - }; - char ifname[64]; - - if (check_params(buf, sizeof(buf), tap_params, p) < 0) { - config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p); - ret = -1; - goto out; - } - if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { - config_error(mon, "tap: no interface name\n"); - ret = -1; - goto out; - } - vlan->nb_host_devs++; - ret = tap_win32_init(vlan, device, name, ifname); - } else -#elif defined (_AIX) -#else - if (!strcmp(device, "tap")) { - char ifname[64], chkbuf[64]; - char setup_script[1024], down_script[1024]; - TAPState *s; - int fd; - vlan->nb_host_devs++; - if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { - static const char * const fd_params[] = { - "vlan", "name", "fd", "sndbuf", NULL - }; - ret = -1; - if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) { - config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); - goto out; - } - fd = net_handle_fd_param(mon, buf); - if (fd == -1) { - goto out; - } - fcntl(fd, F_SETFL, O_NONBLOCK); - s = net_tap_fd_init(vlan, device, name, fd, tap_probe_vnet_hdr(fd)); - if (!s) { - close(fd); - } - } else { - static const char * const tap_params[] = { - "vlan", "name", "ifname", "script", "downscript", "sndbuf", NULL - }; - if (check_params(chkbuf, sizeof(chkbuf), tap_params, p) < 0) { - config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); - ret = -1; - goto out; - } - if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { - ifname[0] = '\0'; - } - if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) { - pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT); - } - if (get_param_value(down_script, sizeof(down_script), "downscript", p) == 0) { - pstrcpy(down_script, sizeof(down_script), DEFAULT_NETWORK_DOWN_SCRIPT); - } - s = net_tap_init(vlan, device, name, ifname, setup_script, down_script); - } - if (s != NULL) { - const char *sndbuf_str = NULL; - if (get_param_value(buf, sizeof(buf), "sndbuf", p)) { - sndbuf_str = buf; - } - tap_set_sndbuf(s, sndbuf_str, mon); ret = 0; } else { - ret = -1; + ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), p, 1); } } else #endif @@ -2874,7 +3059,7 @@ int net_client_init(Monitor *mon, const char *device, const char *p) int fd; ret = -1; if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) { - config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + qemu_error("invalid parameter '%s' in '%s'\n", chkbuf, p); goto out; } fd = net_handle_fd_param(mon, buf); @@ -2891,7 +3076,7 @@ int net_client_init(Monitor *mon, const char *device, const char *p) "vlan", "name", "listen", NULL }; if (check_params(chkbuf, sizeof(chkbuf), listen_params, p) < 0) { - config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + qemu_error("invalid parameter '%s' in '%s'\n", chkbuf, p); ret = -1; goto out; } @@ -2901,7 +3086,7 @@ int net_client_init(Monitor *mon, const char *device, const char *p) "vlan", "name", "connect", NULL }; if (check_params(chkbuf, sizeof(chkbuf), connect_params, p) < 0) { - config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + qemu_error("invalid parameter '%s' in '%s'\n", chkbuf, p); ret = -1; goto out; } @@ -2911,13 +3096,13 @@ int net_client_init(Monitor *mon, const char *device, const char *p) "vlan", "name", "mcast", NULL }; if (check_params(chkbuf, sizeof(chkbuf), mcast_params, p) < 0) { - config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + qemu_error("invalid parameter '%s' in '%s'\n", chkbuf, p); ret = -1; goto out; } ret = net_socket_mcast_init(vlan, device, name, buf); } else { - config_error(mon, "Unknown socket options: %s\n", p); + qemu_error("Unknown socket options: %s\n", p); ret = -1; goto out; } @@ -2932,7 +3117,7 @@ int net_client_init(Monitor *mon, const char *device, const char *p) int vde_port, vde_mode; if (check_params(buf, sizeof(buf), vde_params, p) < 0) { - config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p); + qemu_error("invalid parameter '%s' in '%s'\n", buf, p); ret = -1; goto out; } @@ -2965,14 +3150,14 @@ int net_client_init(Monitor *mon, const char *device, const char *p) if (!get_param_value(buf, sizeof(buf), "file", p)) { snprintf(buf, sizeof(buf), "qemu-vlan%d.pcap", vlan_id); } - ret = net_dump_init(mon, vlan, device, name, buf, len); + ret = net_dump_init(vlan, device, name, buf, len); } else { - config_error(mon, "Unknown network device: %s\n", device); + qemu_error("Unknown network device: %s\n", device); ret = -1; goto out; } if (ret < 0) { - config_error(mon, "Could not initialize device '%s'\n", device); + qemu_error("Could not initialize device '%s'\n", device); } out: qemu_free(name); @@ -2984,12 +3169,12 @@ void net_client_uninit(NICInfo *nd) nd->vlan->nb_guest_devs--; nb_nics--; - qemu_free((void *)nd->model); - qemu_free((void *)nd->name); - qemu_free((void *)nd->devaddr); - qemu_free((void *)nd->id); + qemu_free(nd->model); + qemu_free(nd->name); + qemu_free(nd->devaddr); + qemu_free(nd->id); - memset(nd, 0, sizeof(*nd)); + nd->used = 0; } static int net_host_check_device(const char *device) @@ -103,10 +103,10 @@ enum { struct NICInfo { uint8_t macaddr[6]; - const char *model; - const char *name; - const char *devaddr; - const char *id; + char *model; + char *name; + char *devaddr; + char *id; VLANState *vlan; VLANClientState *vc; void *private; @@ -146,10 +146,10 @@ extern const char *legacy_bootp_filename; int net_client_init(Monitor *mon, const char *device, const char *p); void net_client_uninit(NICInfo *nd); int net_client_parse(const char *str); -void net_slirp_smb(const char *exported_dir); +int net_slirp_smb(const char *exported_dir); void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict); void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict); -void net_slirp_redir(const char *redir_str); +int net_slirp_redir(const char *redir_str); void net_cleanup(void); void net_client_check(void); void net_set_boot_mask(int boot_mask); diff --git a/qemu-config.c b/qemu-config.c index cfb1d2982..a8ce6e716 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -156,6 +156,18 @@ QemuOptsList qemu_device_opts = { }, }; +QemuOptsList qemu_net_opts = { + .name = "net", + .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), + .desc = { + /* + * no elements => accept any params + * validation will happen later + */ + { /* end of list */ } + }, +}; + QemuOptsList qemu_rtc_opts = { .name = "rtc", .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head), @@ -180,6 +192,8 @@ static QemuOptsList *lists[] = { &qemu_drive_opts, &qemu_chardev_opts, &qemu_device_opts, + &qemu_net_opts, + &qemu_rtc_opts, NULL, }; @@ -212,8 +226,6 @@ int qemu_set_option(const char *str) } if (qemu_opt_set(opts, arg, str+offset+1) == -1) { - qemu_error("failed to set \"%s\" for %s \"%s\"\n", - arg, lists[i]->name, id); return -1; } return 0; diff --git a/qemu-config.h b/qemu-config.h index 4ae7b74fe..cdad5ac58 100644 --- a/qemu-config.h +++ b/qemu-config.h @@ -4,6 +4,7 @@ extern QemuOptsList qemu_drive_opts; extern QemuOptsList qemu_chardev_opts; extern QemuOptsList qemu_device_opts; +extern QemuOptsList qemu_net_opts; extern QemuOptsList qemu_rtc_opts; int qemu_set_option(const char *str); diff --git a/qemu-img.texi b/qemu-img.texi index 69e24b598..ae8ca922e 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -37,6 +37,12 @@ Linux or NTFS on Windows), then only the written sectors will reserve space. Use @code{qemu-img info} to know the real size used by the image or @code{ls -ls} on Unix/Linux. +@item host_device + +Host device format. This format should be used instead of raw when +converting to block devices or other devices where "holes" are not +supported. + @item qcow2 QEMU image format, the most versatile format. Use it to have smaller images (useful if your filesystem does not supports holes, for example diff --git a/qemu-option.c b/qemu-option.c index 089228656..49efd392d 100644 --- a/qemu-option.c +++ b/qemu-option.c @@ -483,7 +483,7 @@ struct QemuOpt { struct QemuOpts { const char *id; QemuOptsList *list; - QTAILQ_HEAD(, QemuOpt) head; + QTAILQ_HEAD(QemuOptHead, QemuOpt) head; QTAILQ_ENTRY(QemuOpts) next; }; @@ -491,7 +491,7 @@ static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name) { QemuOpt *opt; - QTAILQ_FOREACH(opt, &opts->head, next) { + QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next) { if (strcmp(opt->name, name) != 0) continue; return opt; @@ -565,36 +565,31 @@ static void qemu_opt_del(QemuOpt *opt) int qemu_opt_set(QemuOpts *opts, const char *name, const char *value) { QemuOpt *opt; + QemuOptDesc *desc = opts->list->desc; + int i; - opt = qemu_opt_find(opts, name); - if (!opt) { - QemuOptDesc *desc = opts->list->desc; - int i; - - for (i = 0; desc[i].name != NULL; i++) { - if (strcmp(desc[i].name, name) == 0) { - break; - } - } - if (desc[i].name == NULL) { - if (i == 0) { - /* empty list -> allow any */; - } else { - fprintf(stderr, "option \"%s\" is not valid for %s\n", - name, opts->list->name); - return -1; - } + for (i = 0; desc[i].name != NULL; i++) { + if (strcmp(desc[i].name, name) == 0) { + break; } - opt = qemu_mallocz(sizeof(*opt)); - opt->name = qemu_strdup(name); - opt->opts = opts; - QTAILQ_INSERT_TAIL(&opts->head, opt, next); - if (desc[i].name != NULL) { - opt->desc = desc+i; + } + if (desc[i].name == NULL) { + if (i == 0) { + /* empty list -> allow any */; + } else { + fprintf(stderr, "option \"%s\" is not valid for %s\n", + name, opts->list->name); + return -1; } } - qemu_free((/* !const */ char*)opt->str); - opt->str = NULL; + + opt = qemu_mallocz(sizeof(*opt)); + opt->name = qemu_strdup(name); + opt->opts = opts; + QTAILQ_INSERT_TAIL(&opts->head, opt, next); + if (desc[i].name != NULL) { + opt->desc = desc+i; + } if (value) { opt->str = qemu_strdup(value); } @@ -670,8 +665,6 @@ int qemu_opts_set(QemuOptsList *list, const char *id, opts = qemu_opts_create(list, id, 1); if (opts == NULL) { - fprintf(stderr, "id \"%s\" not found for \"%s\"\n", - id, list->name); return -1; } return qemu_opt_set(opts, name, value); @@ -714,8 +707,7 @@ int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname char option[128], value[128]; const char *p,*pe,*pc; - p = params; - for(;;) { + for (p = params; *p != '\0'; p++) { pe = strchr(p, '='); pc = strchr(p, ','); if (!pe || (pc && pc < pe)) { @@ -752,7 +744,6 @@ int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname if (*p != ',') { break; } - p++; } return 0; } @@ -782,6 +773,39 @@ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *fi return opts; } +/* Validate parsed opts against descriptions where no + * descriptions were provided in the QemuOptsList. + */ +int qemu_opts_validate(QemuOpts *opts, QemuOptDesc *desc) +{ + QemuOpt *opt; + + assert(opts->list->desc[0].name == NULL); + + QTAILQ_FOREACH(opt, &opts->head, next) { + int i; + + for (i = 0; desc[i].name != NULL; i++) { + if (strcmp(desc[i].name, opt->name) == 0) { + break; + } + } + if (desc[i].name == NULL) { + fprintf(stderr, "option \"%s\" is not valid for %s\n", + opt->name, opts->list->name); + return -1; + } + + opt->desc = &desc[i]; + + if (qemu_opt_parse(opt) < 0) { + return -1; + } + } + + return 0; +} + int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque, int abort_on_failure) { diff --git a/qemu-option.h b/qemu-option.h index 525b9b6f0..666b666b3 100644 --- a/qemu-option.h +++ b/qemu-option.h @@ -115,6 +115,7 @@ int qemu_opts_set(QemuOptsList *list, const char *id, const char *name, const char *value); const char *qemu_opts_id(QemuOpts *opts); void qemu_opts_del(QemuOpts *opts); +int qemu_opts_validate(QemuOpts *opts, 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); diff --git a/qemu-options.hx b/qemu-options.hx index b757295a0..bde3e3f3d 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -479,6 +479,16 @@ Use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt). ETEXI #ifdef CONFIG_SDL +DEF("ctrl-grab", 0, QEMU_OPTION_ctrl_grab, + "-ctrl-grab use Right-Ctrl to grab mouse (instead of Ctrl-Alt)\n") +#endif +STEXI +@item -ctrl-grab + +Use Right-Ctrl to grab mouse (instead of Ctrl-Alt). +ETEXI + +#ifdef CONFIG_SDL DEF("no-quit", 0, QEMU_OPTION_no_quit, "-no-quit disable SDL window close capability\n") #endif @@ -414,10 +414,12 @@ static void sdl_update_caption(void) if (!vm_running) status = " [Stopped]"; else if (gui_grab) { - if (!alt_grab) - status = " - Press Ctrl-Alt to exit grab"; - else + if (alt_grab) status = " - Press Ctrl-Alt-Shift to exit grab"; + else if (ctrl_grab) + status = " - Press Right-Ctrl to exit grab"; + else + status = " - Press Ctrl-Alt to exit grab"; } if (qemu_name) { @@ -557,12 +559,14 @@ static void sdl_refresh(DisplayState *ds) case SDL_KEYDOWN: case SDL_KEYUP: if (ev->type == SDL_KEYDOWN) { - if (!alt_grab) { - mod_state = (SDL_GetModState() & gui_grab_code) == - gui_grab_code; - } else { + if (alt_grab) { mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) == (gui_grab_code | KMOD_LSHIFT); + } else if (ctrl_grab) { + mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL; + } else { + mod_state = (SDL_GetModState() & gui_grab_code) == + gui_grab_code; } gui_key_modifier_pressed = mod_state; if (gui_key_modifier_pressed) { @@ -127,6 +127,7 @@ extern const char *keyboard_layout; extern int win2k_install_hack; extern int rtc_td_hack; extern int alt_grab; +extern int ctrl_grab; extern int usb_enabled; extern int smp_cpus; extern int max_cpus; @@ -260,6 +260,7 @@ int old_param = 0; #endif const char *qemu_name; int alt_grab = 0; +int ctrl_grab = 0; #if defined(TARGET_SPARC) || defined(TARGET_PPC) unsigned int nb_prom_envs = 0; const char *prom_envs[MAX_PROM_ENVS]; @@ -2622,7 +2623,7 @@ static int usb_device_add(const char *devname, int is_hotplug) if (net_client_init(NULL, "nic", p) < 0) return -1; - nd_table[nic].model = "usb"; + nd_table[nic].model = qemu_strdup("usb"); dev = usb_net_init(&nd_table[nic]); } else if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) { dev = usb_bt_init(devname[2] ? hci_init(p) : @@ -5157,11 +5158,13 @@ int main(int argc, char **argv, char **envp) break; #ifndef _WIN32 case QEMU_OPTION_smb: - net_slirp_smb(optarg); + if (net_slirp_smb(optarg) < 0) + exit(1); break; #endif case QEMU_OPTION_redir: - net_slirp_redir(optarg); + if (net_slirp_redir(optarg) < 0) + exit(1); break; #endif case QEMU_OPTION_bt: @@ -5370,6 +5373,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_alt_grab: alt_grab = 1; break; + case QEMU_OPTION_ctrl_grab: + ctrl_grab = 1; + break; case QEMU_OPTION_no_quit: no_quit = 1; break; @@ -5445,9 +5451,7 @@ int main(int argc, char **argv, char **envp) add_device_config(DEV_USB, optarg); break; case QEMU_OPTION_device: - opts = qemu_opts_parse(&qemu_device_opts, optarg, "driver"); - if (!opts) { - fprintf(stderr, "parse error: %s\n", optarg); + if (!qemu_opts_parse(&qemu_device_opts, optarg, "driver")) { exit(1); } break; @@ -5958,7 +5962,8 @@ int main(int argc, char **argv, char **envp) /* init USB devices */ if (usb_enabled) { - foreach_device_config(DEV_USB, usb_parse); + if (foreach_device_config(DEV_USB, usb_parse) < 0) + exit(1); } /* init generic devices */ |