diff mbox series

[v2] qemu-config: add error propagation to qemu_config_parse

Message ID 20210226170816.231173-1-pbonzini@redhat.com
State New
Headers show
Series [v2] qemu-config: add error propagation to qemu_config_parse | expand

Commit Message

Paolo Bonzini Feb. 26, 2021, 5:08 p.m. UTC
This enables some simplification of vl.c via error_fatal, and improves
error messages.  Before:

Before:
  $ ./qemu-system-x86_64 -readconfig .
  qemu-system-x86_64: error reading file
  qemu-system-x86_64: -readconfig .: read config .: Invalid argument
  $ /usr/libexec/qemu-kvm -readconfig foo
  qemu-kvm: -readconfig foo: read config foo: No such file or directory

After:

  $ ./qemu-system-x86_64 -readconfig .
  qemu-system-x86_64: -readconfig .: error reading file: Is a directory
  $ ./qemu-system-x86_64 -readconfig foo
  qemu-system-x86_64: -readconfig foo: Cannot read config file foo: No such file or directory

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 block/blkdebug.c           |  3 +--
 include/qemu/config-file.h |  5 +++--
 softmmu/vl.c               | 29 +++++++++++------------------
 util/qemu-config.c         | 23 ++++++++++++-----------
 4 files changed, 27 insertions(+), 33 deletions(-)

Comments

Philippe Mathieu-Daudé Feb. 26, 2021, 5:46 p.m. UTC | #1
On 2/26/21 6:08 PM, Paolo Bonzini wrote:
> This enables some simplification of vl.c via error_fatal, and improves
> error messages.  Before:
> 
> Before:
>   $ ./qemu-system-x86_64 -readconfig .
>   qemu-system-x86_64: error reading file
>   qemu-system-x86_64: -readconfig .: read config .: Invalid argument
>   $ /usr/libexec/qemu-kvm -readconfig foo
>   qemu-kvm: -readconfig foo: read config foo: No such file or directory
> 
> After:
> 
>   $ ./qemu-system-x86_64 -readconfig .
>   qemu-system-x86_64: -readconfig .: error reading file: Is a directory
>   $ ./qemu-system-x86_64 -readconfig foo
>   qemu-system-x86_64: -readconfig foo: Cannot read config file foo: No such file or directory
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  block/blkdebug.c           |  3 +--
>  include/qemu/config-file.h |  5 +++--
>  softmmu/vl.c               | 29 +++++++++++------------------
>  util/qemu-config.c         | 23 ++++++++++++-----------
>  4 files changed, 27 insertions(+), 33 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Markus Armbruster March 3, 2021, 1:48 p.m. UTC | #2
Paolo Bonzini <pbonzini@redhat.com> writes:

> This enables some simplification of vl.c via error_fatal, and improves
> error messages.  Before:
>
> Before:
>   $ ./qemu-system-x86_64 -readconfig .
>   qemu-system-x86_64: error reading file
>   qemu-system-x86_64: -readconfig .: read config .: Invalid argument
>   $ /usr/libexec/qemu-kvm -readconfig foo
>   qemu-kvm: -readconfig foo: read config foo: No such file or directory
>
> After:
>
>   $ ./qemu-system-x86_64 -readconfig .
>   qemu-system-x86_64: -readconfig .: error reading file: Is a directory
>   $ ./qemu-system-x86_64 -readconfig foo
>   qemu-system-x86_64: -readconfig foo: Cannot read config file foo: No such file or directory
>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Lovely :)

> ---
>  block/blkdebug.c           |  3 +--
>  include/qemu/config-file.h |  5 +++--
>  softmmu/vl.c               | 29 +++++++++++------------------
>  util/qemu-config.c         | 23 ++++++++++++-----------
>  4 files changed, 27 insertions(+), 33 deletions(-)
>
> diff --git a/block/blkdebug.c b/block/blkdebug.c
> index 5fe6172da9..7eaa8a28bf 100644
> --- a/block/blkdebug.c
> +++ b/block/blkdebug.c
> @@ -279,9 +279,8 @@ static int read_config(BDRVBlkdebugState *s, const char *filename,
>              return -errno;
>          }
>  
> -        ret = qemu_config_parse(f, config_groups, filename);
> +        ret = qemu_config_parse(f, config_groups, filename, errp);
>          if (ret < 0) {
> -            error_setg(errp, "Could not parse blkdebug config file");
>              goto fail;
>          }
>      }
> diff --git a/include/qemu/config-file.h b/include/qemu/config-file.h
> index 29226107bd..8d3e53ae4d 100644
> --- a/include/qemu/config-file.h
> +++ b/include/qemu/config-file.h
> @@ -11,9 +11,10 @@ void qemu_add_drive_opts(QemuOptsList *list);
>  int qemu_global_option(const char *str);
>  
>  void qemu_config_write(FILE *fp);
> -int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname);
> +int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname,
> +                      Error **errp);
>  
> -int qemu_read_config_file(const char *filename);
> +int qemu_read_config_file(const char *filename, Error **errp);
>  
>  /* Parse QDict options as a replacement for a config file (allowing multiple
>     enumerated (0..(n-1)) configuration "sections") */
> diff --git a/softmmu/vl.c b/softmmu/vl.c
> index e67f91dd37..e80859c40d 100644
> --- a/softmmu/vl.c
> +++ b/softmmu/vl.c
> @@ -2062,17 +2062,19 @@ static int global_init_func(void *opaque, QemuOpts *opts, Error **errp)
>      return 0;
>  }
>  
> -static int qemu_read_default_config_file(void)
> +static void qemu_read_default_config_file(Error **errp)
>  {
> +    ERRP_GUARD();
>      int ret;
>      g_autofree char *file = get_relocated_path(CONFIG_QEMU_CONFDIR "/qemu.conf");
>  
> -    ret = qemu_read_config_file(file);
> -    if (ret < 0 && ret != -ENOENT) {
> -        return ret;
> +    ret = qemu_read_config_file(file, errp);
> +    if (ret < 0) {
> +        if (ret == -ENOENT) {
> +            error_free(*errp);
> +            *errp = NULL;
> +        }
>      }
> -
> -    return 0;
>  }

This change to return void goes against advice in error.h:

 * - Whenever practical, also return a value that indicates success /
 *   failure.  This can make the error checking more concise, and can
 *   avoid useless error object creation and destruction.  Note that
 *   we still have many functions returning void.  We recommend
 *   • bool-valued functions return true on success / false on failure,
 *   • pointer-valued functions return non-null / null pointer, and
 *   • integer-valued functions return non-negative / negative.

Tolerable.  The only caller wouldn't profit from a return value (it
passes &error_fatal), and more callers seem quite unlikely.

>  
>  static int qemu_set_option(const char *str)
> @@ -2640,9 +2642,7 @@ void qemu_init(int argc, char **argv, char **envp)
>      }
>  
>      if (userconfig) {
> -        if (qemu_read_default_config_file() < 0) {
> -            exit(1);
> -        }
> +        qemu_read_default_config_file(&error_fatal);
>      }
>  
>      /* second pass of option parsing */
> @@ -3330,15 +3330,8 @@ void qemu_init(int argc, char **argv, char **envp)
>                  qemu_plugin_opt_parse(optarg, &plugin_list);
>                  break;
>              case QEMU_OPTION_readconfig:
> -                {
> -                    int ret = qemu_read_config_file(optarg);
> -                    if (ret < 0) {
> -                        error_report("read config %s: %s", optarg,
> -                                     strerror(-ret));
> -                        exit(1);
> -                    }
> -                    break;
> -                }
> +                qemu_read_config_file(optarg, &error_fatal);
> +                break;
>              case QEMU_OPTION_spice:
>                  olist = qemu_find_opts_err("spice", NULL);
>                  if (!olist) {
> diff --git a/util/qemu-config.c b/util/qemu-config.c
> index e2a700b284..af89df109d 100644
> --- a/util/qemu-config.c
> +++ b/util/qemu-config.c
> @@ -350,7 +350,7 @@ void qemu_config_write(FILE *fp)
>  }
>  
>  /* Returns number of config groups on success, -errno on error */
> -int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
> +int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp)
>  {
>      char line[1024], group[64], id[64], arg[64], value[1024];
>      Location loc;
> @@ -375,7 +375,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
>              /* group with id */
>              list = find_list(lists, group, &local_err);
>              if (local_err) {
> -                error_report_err(local_err);
> +                error_propagate(errp, local_err);
>                  goto out;
>              }

Please avoid error_propagate() where possible:

               list = find_list(lists, group, errp);
               if (!list) {
                   goto out;
               }

>              opts = qemu_opts_create(list, id, 1, NULL);
> @@ -386,7 +386,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
>              /* group without id */
>              list = find_list(lists, group, &local_err);
>              if (local_err) {
> -                error_report_err(local_err);
> +                error_propagate(errp, local_err);
>                  goto out;
>              }

Likewise.

>              opts = qemu_opts_create(list, NULL, 0, &error_abort);
> @@ -398,21 +398,21 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
>              sscanf(line, " %63s = \"\"", arg) == 1) {
>              /* arg = value */
>              if (opts == NULL) {
> -                error_report("no group defined");
> +                error_setg(errp, "no group defined");
>                  goto out;
>              }
> -            if (!qemu_opt_set(opts, arg, value, &local_err)) {
> -                error_report_err(local_err);
> +            if (!qemu_opt_set(opts, arg, value, errp)) {
>                  goto out;
>              }
>              continue;
>          }
> -        error_report("parse error");
> +        error_setg(errp, "parse error");
>          goto out;
>      }
>      if (ferror(fp)) {
> -        error_report("error reading file");
> -        goto out;
> +        loc_pop(&loc);
> +        error_setg_errno(errp, errno, "error reading file");
> +        return res;
>      }
>      res = count;
>  out:
> @@ -420,16 +420,17 @@ out:
>      return res;
>  }
>  
> -int qemu_read_config_file(const char *filename)
> +int qemu_read_config_file(const char *filename, Error **errp)
>  {
>      FILE *f = fopen(filename, "r");
>      int ret;
>  
>      if (f == NULL) {
> +        error_setg_errno(errp, errno, "Cannot read config file %s", filename);
>          return -errno;
>      }
>  
> -    ret = qemu_config_parse(f, vm_config_groups, filename);
> +    ret = qemu_config_parse(f, vm_config_groups, filename, errp);
>      fclose(f);
>      return ret;
>  }

Not avoiding error_propagate() isn't wrong, so
Reviewed-by: Markus Armbruster <armbru@redhat.com>

But please consider avoiding it anyway.
Paolo Bonzini March 3, 2021, 1:55 p.m. UTC | #3
On 03/03/21 14:48, Markus Armbruster wrote:
> Reviewed-by: Markus Armbruster<armbru@redhat.com>
> 
> But please consider avoiding it anyway.

It does make for a smaller patch, so I'll use that as an excuse instead 
of me being old school.  I'll clean it up in a separate patch.

Paolo
diff mbox series

Patch

diff --git a/block/blkdebug.c b/block/blkdebug.c
index 5fe6172da9..7eaa8a28bf 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -279,9 +279,8 @@  static int read_config(BDRVBlkdebugState *s, const char *filename,
             return -errno;
         }
 
-        ret = qemu_config_parse(f, config_groups, filename);
+        ret = qemu_config_parse(f, config_groups, filename, errp);
         if (ret < 0) {
-            error_setg(errp, "Could not parse blkdebug config file");
             goto fail;
         }
     }
diff --git a/include/qemu/config-file.h b/include/qemu/config-file.h
index 29226107bd..8d3e53ae4d 100644
--- a/include/qemu/config-file.h
+++ b/include/qemu/config-file.h
@@ -11,9 +11,10 @@  void qemu_add_drive_opts(QemuOptsList *list);
 int qemu_global_option(const char *str);
 
 void qemu_config_write(FILE *fp);
-int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname);
+int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname,
+                      Error **errp);
 
-int qemu_read_config_file(const char *filename);
+int qemu_read_config_file(const char *filename, Error **errp);
 
 /* Parse QDict options as a replacement for a config file (allowing multiple
    enumerated (0..(n-1)) configuration "sections") */
diff --git a/softmmu/vl.c b/softmmu/vl.c
index e67f91dd37..e80859c40d 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -2062,17 +2062,19 @@  static int global_init_func(void *opaque, QemuOpts *opts, Error **errp)
     return 0;
 }
 
-static int qemu_read_default_config_file(void)
+static void qemu_read_default_config_file(Error **errp)
 {
+    ERRP_GUARD();
     int ret;
     g_autofree char *file = get_relocated_path(CONFIG_QEMU_CONFDIR "/qemu.conf");
 
-    ret = qemu_read_config_file(file);
-    if (ret < 0 && ret != -ENOENT) {
-        return ret;
+    ret = qemu_read_config_file(file, errp);
+    if (ret < 0) {
+        if (ret == -ENOENT) {
+            error_free(*errp);
+            *errp = NULL;
+        }
     }
-
-    return 0;
 }
 
 static int qemu_set_option(const char *str)
@@ -2640,9 +2642,7 @@  void qemu_init(int argc, char **argv, char **envp)
     }
 
     if (userconfig) {
-        if (qemu_read_default_config_file() < 0) {
-            exit(1);
-        }
+        qemu_read_default_config_file(&error_fatal);
     }
 
     /* second pass of option parsing */
@@ -3330,15 +3330,8 @@  void qemu_init(int argc, char **argv, char **envp)
                 qemu_plugin_opt_parse(optarg, &plugin_list);
                 break;
             case QEMU_OPTION_readconfig:
-                {
-                    int ret = qemu_read_config_file(optarg);
-                    if (ret < 0) {
-                        error_report("read config %s: %s", optarg,
-                                     strerror(-ret));
-                        exit(1);
-                    }
-                    break;
-                }
+                qemu_read_config_file(optarg, &error_fatal);
+                break;
             case QEMU_OPTION_spice:
                 olist = qemu_find_opts_err("spice", NULL);
                 if (!olist) {
diff --git a/util/qemu-config.c b/util/qemu-config.c
index e2a700b284..af89df109d 100644
--- a/util/qemu-config.c
+++ b/util/qemu-config.c
@@ -350,7 +350,7 @@  void qemu_config_write(FILE *fp)
 }
 
 /* Returns number of config groups on success, -errno on error */
-int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
+int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp)
 {
     char line[1024], group[64], id[64], arg[64], value[1024];
     Location loc;
@@ -375,7 +375,7 @@  int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
             /* group with id */
             list = find_list(lists, group, &local_err);
             if (local_err) {
-                error_report_err(local_err);
+                error_propagate(errp, local_err);
                 goto out;
             }
             opts = qemu_opts_create(list, id, 1, NULL);
@@ -386,7 +386,7 @@  int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
             /* group without id */
             list = find_list(lists, group, &local_err);
             if (local_err) {
-                error_report_err(local_err);
+                error_propagate(errp, local_err);
                 goto out;
             }
             opts = qemu_opts_create(list, NULL, 0, &error_abort);
@@ -398,21 +398,21 @@  int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
             sscanf(line, " %63s = \"\"", arg) == 1) {
             /* arg = value */
             if (opts == NULL) {
-                error_report("no group defined");
+                error_setg(errp, "no group defined");
                 goto out;
             }
-            if (!qemu_opt_set(opts, arg, value, &local_err)) {
-                error_report_err(local_err);
+            if (!qemu_opt_set(opts, arg, value, errp)) {
                 goto out;
             }
             continue;
         }
-        error_report("parse error");
+        error_setg(errp, "parse error");
         goto out;
     }
     if (ferror(fp)) {
-        error_report("error reading file");
-        goto out;
+        loc_pop(&loc);
+        error_setg_errno(errp, errno, "error reading file");
+        return res;
     }
     res = count;
 out:
@@ -420,16 +420,17 @@  out:
     return res;
 }
 
-int qemu_read_config_file(const char *filename)
+int qemu_read_config_file(const char *filename, Error **errp)
 {
     FILE *f = fopen(filename, "r");
     int ret;
 
     if (f == NULL) {
+        error_setg_errno(errp, errno, "Cannot read config file %s", filename);
         return -errno;
     }
 
-    ret = qemu_config_parse(f, vm_config_groups, filename);
+    ret = qemu_config_parse(f, vm_config_groups, filename, errp);
     fclose(f);
     return ret;
 }