diff mbox

[05/11] acpi_table_add(): accept QemuOpts and parse it with OptsVisitor

Message ID 1363821803-3380-6-git-send-email-lersek@redhat.com
State New
Headers show

Commit Message

Laszlo Ersek March 20, 2013, 11:23 p.m. UTC
As one consequence, strtok() -- which modifies its argument -- is replaced
with g_strsplit().

Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 hw/pc.h                    |    2 +-
 include/sysemu/arch_init.h |    3 +-
 arch_init.c                |    4 +-
 hw/acpi.c                  |  139 ++++++++++++++++++++++++++------------------
 hw/i386/pc.c               |    9 +++-
 vl.c                       |    4 +-
 6 files changed, 98 insertions(+), 63 deletions(-)
diff mbox

Patch

diff --git a/hw/pc.h b/hw/pc.h
index fe1768b..7aaba3c 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -113,7 +113,7 @@  extern char unsigned *acpi_tables;
 extern size_t acpi_tables_len;
 
 void acpi_bios_init(void);
-int acpi_table_add(const char *table_desc);
+int acpi_table_add(const QemuOpts *opts);
 
 /* acpi_piix.c */
 
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index 5fc780c..24d8946 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -2,6 +2,7 @@ 
 #define QEMU_ARCH_INIT_H
 
 #include "qmp-commands.h"
+#include "qemu/option.h"
 
 enum {
     QEMU_ARCH_ALL = -1,
@@ -25,7 +26,7 @@  enum {
 extern const uint32_t arch_type;
 
 void select_soundhw(const char *optarg);
-void do_acpitable_option(const char *optarg);
+void do_acpitable_option(const QemuOpts *opts);
 void do_smbios_option(const char *optarg);
 void cpudef_init(void);
 int audio_available(void);
diff --git a/arch_init.c b/arch_init.c
index 761051b..d6170f7 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -1105,10 +1105,10 @@  int qemu_uuid_parse(const char *str, uint8_t *uuid)
     return 0;
 }
 
-void do_acpitable_option(const char *optarg)
+void do_acpitable_option(const QemuOpts *opts)
 {
 #ifdef TARGET_I386
-    if (acpi_table_add(optarg) < 0) {
+    if (acpi_table_add(opts) < 0) {
         fprintf(stderr, "Wrong acpi table provided\n");
         exit(1);
     }
diff --git a/hw/acpi.c b/hw/acpi.c
index f34fcde..b29dada 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -23,6 +23,10 @@ 
 #include "hw/pc.h"
 #include "hw/acpi.h"
 #include "monitor/monitor.h"
+#include "qemu/config-file.h"
+#include "qapi/opts-visitor.h"
+#include "qapi/dealloc-visitor.h"
+#include "qapi-visit.h"
 
 struct acpi_table_header {
     uint16_t _length;         /* our length, not actual part of the hdr */
@@ -51,6 +55,20 @@  static const char unsigned dfl_hdr[ACPI_TABLE_HDR_SIZE] =
 char unsigned *acpi_tables;
 size_t acpi_tables_len;
 
+static QemuOptsList qemu_acpi_opts = {
+    .name = "acpi",
+    .implied_opt_name = "data",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_acpi_opts.head),
+    .desc = { { 0 } } /* validated with OptsVisitor */
+};
+
+static void acpi_register_config(void)
+{
+    qemu_add_opts(&qemu_acpi_opts);
+}
+
+machine_init(acpi_register_config);
+
 static int acpi_checksum(const uint8_t *data, int len)
 {
     int sum, i;
@@ -61,12 +79,13 @@  static int acpi_checksum(const uint8_t *data, int len)
     return (-sum) & 0xff;
 }
 
-/* XXX fixme: this function uses obsolete argument parsing interface */
-int acpi_table_add(const char *t)
+int acpi_table_add(const QemuOpts *opts)
 {
+    AcpiTableOptions *hdrs = NULL;
     Error *err = NULL;
-    char buf[1024], *p, *f;
-    unsigned long val;
+    char **pathnames = NULL;
+    char **cur;
+
     size_t len, start, allen;
     bool has_header;
     int changed;
@@ -74,21 +93,26 @@  int acpi_table_add(const char *t)
     struct acpi_table_header hdr;
     char unsigned *table_start;
 
-    r = 0;
-    r |= get_param_value(buf, sizeof(buf), "data", t) ? 1 : 0;
-    r |= get_param_value(buf, sizeof(buf), "file", t) ? 2 : 0;
-    switch (r) {
-    case 0:
-        buf[0] = '\0';
-        /* fallthrough for default behavior */
-    case 1:
-        has_header = false;
-        break;
-    case 2:
-        has_header = true;
-        break;
-    default:
-        error_setg(&err, "acpitable: both data and file are specified");
+    {
+        OptsVisitor *ov;
+
+        ov = opts_visitor_new(opts);
+        visit_type_AcpiTableOptions(opts_get_visitor(ov), &hdrs, NULL, &err);
+        opts_visitor_cleanup(ov);
+    }
+
+    if (err) {
+        goto out;
+    }
+    if (hdrs->has_file == hdrs->has_data) {
+        error_setg(&err, "'-acpitable' requires one of 'data' or 'file'");
+        goto out;
+    }
+    has_header = hdrs->has_file;
+
+    pathnames = g_strsplit(hdrs->has_file ? hdrs->file : hdrs->data, ":", 0);
+    if (pathnames == NULL || pathnames[0] == NULL) {
+        error_setg(&err, "'-acpitable' requires at least one pathname");
         goto out;
     }
 
@@ -105,11 +129,11 @@  int acpi_table_add(const char *t)
 
     /* now read in the data files, reallocating buffer as needed */
 
-    for (f = strtok(buf, ":"); f; f = strtok(NULL, ":")) {
-        int fd = open(f, O_RDONLY | O_BINARY);
+    for (cur = pathnames; *cur; ++cur) {
+        int fd = open(*cur, O_RDONLY | O_BINARY);
 
         if (fd < 0) {
-            error_setg(&err, "can't open file %s: %s", f, strerror(errno));
+            error_setg(&err, "can't open file %s: %s", *cur, strerror(errno));
             goto out;
         }
 
@@ -124,7 +148,7 @@  int acpi_table_add(const char *t)
                 allen += r;
             } else if (errno != EINTR) {
                 error_setg(&err, "can't read file %s: %s",
-                           f, strerror(errno));
+                           *cur, strerror(errno));
                 close(fd);
                 goto out;
             }
@@ -146,14 +170,16 @@  int acpi_table_add(const char *t)
 
     hdr._length = cpu_to_le16(len);
 
-    if (get_param_value(buf, sizeof(buf), "sig", t)) {
+    if (hdrs->has_sig) {
         /* strncpy is justified: the field need not be NUL-terminated. */
-        strncpy(hdr.sig, buf, sizeof(hdr.sig));
+        strncpy(hdr.sig, hdrs->sig, sizeof(hdr.sig));
         ++changed;
     }
 
     /* length of the table including header, in bytes */
     if (has_header) {
+        unsigned long val;
+
         /* check if actual length is correct */
         val = le32_to_cpu(hdr.length);
         if (val != len) {
@@ -167,52 +193,38 @@  int acpi_table_add(const char *t)
     /* we may avoid putting length here if has_header is true */
     hdr.length = cpu_to_le32(len);
 
-    if (get_param_value(buf, sizeof(buf), "rev", t)) {
-        val = strtoul(buf, &p, 0);
-        if (val > 255 || *p) {
-            error_setg(&err, "acpitable: \"rev=%s\" is invalid", buf);
-            goto out;
-        }
-        hdr.revision = (uint8_t)val;
+    if (hdrs->has_rev) {
+        hdr.revision = hdrs->rev;
         ++changed;
     }
 
-    if (get_param_value(buf, sizeof(buf), "oem_id", t)) {
+    if (hdrs->has_oem_id) {
         /* strncpy is justified: the field need not be NUL-terminated. */
-        strncpy(hdr.oem_id, buf, sizeof(hdr.oem_id));
+        strncpy(hdr.oem_id, hdrs->oem_id, sizeof(hdr.oem_id));
         ++changed;
     }
 
-    if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) {
+    if (hdrs->has_oem_table_id) {
         /* strncpy is justified: the field need not be NUL-terminated. */
-        strncpy(hdr.oem_table_id, buf, sizeof(hdr.oem_table_id));
+        strncpy(hdr.oem_table_id, hdrs->oem_table_id,
+                sizeof(hdr.oem_table_id));
         ++changed;
     }
 
-    if (get_param_value(buf, sizeof(buf), "oem_rev", t)) {
-        val = strtol(buf, &p, 0);
-        if (*p) {
-            error_setg(&err, "acpitable: \"oem_rev=%s\" is invalid", buf);
-            goto out;
-        }
-        hdr.oem_revision = cpu_to_le32(val);
+    if (hdrs->has_oem_rev) {
+        hdr.oem_revision = cpu_to_le32(hdrs->oem_rev);
         ++changed;
     }
 
-    if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) {
+    if (hdrs->has_asl_compiler_id) {
         /* strncpy is justified: the field need not be NUL-terminated. */
-        strncpy(hdr.asl_compiler_id, buf, sizeof(hdr.asl_compiler_id));
+        strncpy(hdr.asl_compiler_id, hdrs->asl_compiler_id,
+                sizeof(hdr.asl_compiler_id));
         ++changed;
     }
 
-    if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) {
-        val = strtol(buf, &p, 0);
-        if (*p) {
-            error_setg(&err, "acpitable: \"%s=%s\" is invalid",
-                       "asl_compiler_rev", buf);
-            goto out;
-        }
-        hdr.asl_compiler_revision = cpu_to_le32(val);
+    if (hdrs->has_asl_compiler_rev) {
+        hdr.asl_compiler_revision = cpu_to_le32(hdrs->asl_compiler_rev);
         ++changed;
     }
 
@@ -239,12 +251,25 @@  int acpi_table_add(const char *t)
         cpu_to_le32(le32_to_cpu(*(uint16_t *)acpi_tables) + 1);
 
     acpi_tables_len = allen;
-    return 0;
 
 out:
-    fprintf(stderr, "%s\n", error_get_pretty(err));
-    error_free(err);
-    return -1;
+    g_strfreev(pathnames);
+
+    if (hdrs != NULL) {
+        QapiDeallocVisitor *dv;
+
+        dv = qapi_dealloc_visitor_new();
+        visit_type_AcpiTableOptions(qapi_dealloc_get_visitor(dv), &hdrs, NULL,
+                                    NULL);
+        qapi_dealloc_visitor_cleanup(dv);
+    }
+
+    if (err) {
+        fprintf(stderr, "%s\n", error_get_pretty(err));
+        error_free(err);
+        return -1;
+    }
+    return 0;
 }
 
 static void acpi_notify_wakeup(Notifier *notifier, void *data)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index ed7d9ba..bba19e4 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -51,6 +51,7 @@ 
 #include "exec/address-spaces.h"
 #include "sysemu/arch_init.h"
 #include "qemu/bitmap.h"
+#include "qemu/config-file.h"
 
 /* debug PC/ISA interrupts */
 //#define DEBUG_IRQ
@@ -886,6 +887,7 @@  void pc_cpus_init(const char *cpu_model)
 void pc_acpi_init(const char *default_dsdt)
 {
     char *filename = NULL, *arg = NULL;
+    QemuOpts *opts;
 
     if (acpi_tables != NULL) {
         /* manually set via -acpitable, leave it alone */
@@ -899,7 +901,12 @@  void pc_acpi_init(const char *default_dsdt)
     }
 
     arg = g_strdup_printf("file=%s", filename);
-    if (acpi_table_add(arg) != 0) {
+
+    /* creates a deep copy of "arg" */
+    opts = qemu_opts_parse(qemu_find_opts("acpi"), arg, 0);
+    g_assert(opts != NULL);
+
+    if (acpi_table_add(opts) != 0) {
         fprintf(stderr, "WARNING: failed to load %s\n", filename);
     }
     g_free(arg);
diff --git a/vl.c b/vl.c
index f2bd893..75c5b60 100644
--- a/vl.c
+++ b/vl.c
@@ -3556,7 +3556,9 @@  int main(int argc, char **argv, char **envp)
                 break;
             }
             case QEMU_OPTION_acpitable:
-                do_acpitable_option(optarg);
+                opts = qemu_opts_parse(qemu_find_opts("acpi"), optarg, 1);
+                g_assert(opts != NULL);
+                do_acpitable_option(opts);
                 break;
             case QEMU_OPTION_smbios:
                 do_smbios_option(optarg);