<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p>It also just occurred to me that the BLS filename itself minus
      the '.conf' extension should also be used as a comparison for the
      is_default check from this line in the spec:</p>
    <p>
      <blockquote type="cite"><span style="color: rgb(0, 0, 0);
          font-family: "Times New Roman"; font-size: 16.16px;
          font-style: normal; font-variant-ligatures: normal;
          font-variant-caps: normal; font-weight: 400; letter-spacing:
          normal; orphans: 2; text-align: start; text-indent: 0px;
          text-transform: none; white-space: normal; widows: 2;
          word-spacing: 0px; -webkit-text-stroke-width: 0px;
          background-color: rgb(255, 255, 255); text-decoration-style:
          initial; text-decoration-color: initial; display: inline
          !important; float: none;">The file name of the file is used
          for identification of the boot item, but shall never be
          presented to the user in the UI.</span></blockquote>
      And possibly even used as the basis for option->id rather than
      state->image?<br>
    </p>
    <br>
    <div class="moz-cite-prefix">On 21/03/18 08:45, Brett Grandbois
      wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:3e40d783-f9e7-e798-819f-859f0c4ab123@opengear.com">[This
      sender failed our fraud detection checks and may not be who they
      appear to be. Learn about spoofing at
      <a class="moz-txt-link-freetext" href="http://aka.ms/LearnAboutSpoofing">http://aka.ms/LearnAboutSpoofing</a>]
      <br>
      <br>
      Tested it out and it works.  I just noticed however that there is
      no
      <br>
      support for default in it so somewhere in bls_finish it would be
      nice to
      <br>
      have an option->is_default check.  The concept of index doesn't
      seem to
      <br>
      apply in BLS like it does in a list of menuentries so probably the
      best
      <br>
      way to go is to do the default env comparison on title or
      machine_id if
      <br>
      either exist.
      <br>
      <br>
      I know I originally suggested it, but looking at the
      implementation I
      <br>
      can see that having option->name be a mash up of machine_id and
      version
      <br>
      isn't the way to go.  It looks much cleaner to just have:
      <br>
      <br>
      if title
      <br>
      <br>
      else if machine_id
      <br>
      <br>
      else if version
      <br>
      <br>
      else
      <br>
      <br>
      <br>
      which then makes the default check easy has you can do it based on
      an
      <br>
      option->name comparison afterwards.
      <br>
      <br>
      Brett
      <br>
      <br>
      <br>
      On 19/03/18 19:27, Javier Martinez Canillas wrote:
      <br>
      <blockquote type="cite">The BootLoaderSpec (BLS) defines a file
        format for boot configurations,
        <br>
        so bootloaders can parse these files and create their boot menu
        entries
        <br>
        by using the information provided by them [0].
        <br>
        <br>
        This allow to configure the boot items as drop-in files in a
        directory
        <br>
        instead of having to parse and modify a bootloader configuration
        file.
        <br>
        <br>
        The GRUB 2 bootloader provides a blscfg command that parses
        these files
        <br>
        and creates menu entries using this information. Add support for
        it.
        <br>
        <br>
        [0]:
        <a class="moz-txt-link-freetext" href="https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/">https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/</a>
        <br>
        <br>
        Signed-off-by: Javier Martinez Canillas
        <a class="moz-txt-link-rfc2396E" href="mailto:javierm@redhat.com"><javierm@redhat.com></a>
        <br>
        <br>
        ---
        <br>
        <br>
        Hello,
        <br>
        <br>
         From Fedora 28 there will be an option to use BootLoaderSpec
        snippets to
        <br>
        update GRUB's boot menu entries. So I'm posting this patch to
        allow this
        <br>
        to also work on ppc64 machines using petitboot, instead of
        grub-ieee1275.
        <br>
        <br>
        This can be tested by creating a BLS config under
        /boot/loader/entries,
        <br>
        for example following
        /boot/loader/entries/4.15.6-300.fc27.x86_64.conf:
        <br>
        <br>
        title Fedora (4.15.6-300.fc27.x86_64) 27 (Twenty Seven)
        <br>
        linux /vmlinuz-4.15.6-300.fc27.x86_64
        <br>
        initrd /initramfs-4.15.6-300.fc27.x86_64.img
        <br>
        options root=/dev/mapper/fedora-root ro rd.lvm.lv=fedora/root
        rd.luks.uuid=luks-0b078909-4a1c-4a57-91b8-b9f724e86a1a
        rd.lvm.lv=fedora/swap rhgb quiet LANG=en_US.UTF-8
        <br>
        id fedora-20180214051518-4.15.6-300.fc27.x86_64.x86_64
        <br>
        grub_users $grub_users
        <br>
        grub_arg --unrestricted
        <br>
        grub_class kernel
        <br>
        <br>
        And a grub.cfg that calls the blscfg command, it could just be
        the following:
        <br>
        <br>
        blscfg
        <br>
        <br>
        Best regards,
        <br>
        Javier
        <br>
        <br>
        Changes in v3:
        <br>
        - Populate boot option id using the linux field instead of title
        field.
        <br>
        - Don't fill boot option name using the optional title field,
        instead
        <br>
           fill this from optional fields that are present in the BLS
        fragment.
        <br>
        - Add support for the devicetree field.
        <br>
        <br>
        Changes in v2:
        <br>
        - Allow optional fields, only require the linux field to be
        present.
        <br>
        - Remove unused identifier from bls_filter() struct dirent *
        param.
        <br>
        - Remove redundant check in builtin_blscfg() while loop.
        <br>
        <br>
          discover/grub2/Makefile.am                   |   1 +
        <br>
          discover/grub2/blscfg.c                      | 221
        +++++++++++++++++++++++++++
        <br>
          discover/grub2/builtins.c                    |   9 +-
        <br>
          discover/parser.c                            |  16 ++
        <br>
          discover/parser.h                            |   8 +
        <br>
          test/parser/Makefile.am                      |   3 +
        <br>
          test/parser/test-grub2-blscfg-multiple-bls.c |  44 ++++++
        <br>
          test/parser/test-grub2-blscfg-opts-config.c  |  29 ++++
        <br>
          test/parser/test-grub2-blscfg-opts-grubenv.c |  34 +++++
        <br>
          test/parser/utils.c                          |  59 +++++++
        <br>
          10 files changed, 423 insertions(+), 1 deletion(-)
        <br>
          create mode 100644 discover/grub2/blscfg.c
        <br>
          create mode 100644
        test/parser/test-grub2-blscfg-multiple-bls.c
        <br>
          create mode 100644 test/parser/test-grub2-blscfg-opts-config.c
        <br>
          create mode 100644
        test/parser/test-grub2-blscfg-opts-grubenv.c
        <br>
        <br>
        diff --git a/discover/grub2/Makefile.am
        b/discover/grub2/Makefile.am
        <br>
        index 130ede88e18c..b240106d7a54 100644
        <br>
        --- a/discover/grub2/Makefile.am
        <br>
        +++ b/discover/grub2/Makefile.am
        <br>
        @@ -15,6 +15,7 @@
        <br>
          noinst_PROGRAMS += discover/grub2/grub2-parser.ro
        <br>
        <br>
          discover_grub2_grub2_parser_ro_SOURCES = \
        <br>
        +     discover/grub2/blscfg.c \
        <br>
              discover/grub2/builtins.c \
        <br>
              discover/grub2/env.c \
        <br>
              discover/grub2/grub2.h \
        <br>
        diff --git a/discover/grub2/blscfg.c b/discover/grub2/blscfg.c
        <br>
        new file mode 100644
        <br>
        index 000000000000..5677aa081531
        <br>
        --- /dev/null
        <br>
        +++ b/discover/grub2/blscfg.c
        <br>
        @@ -0,0 +1,221 @@
        <br>
        +
        <br>
        +#define _GNU_SOURCE
        <br>
        +
        <br>
        +#include <assert.h>
        <br>
        +#include <stdlib.h>
        <br>
        +#include <string.h>
        <br>
        +#include <dirent.h>
        <br>
        +
        <br>
        +#include <log/log.h>
        <br>
        +#include <file/file.h>
        <br>
        +#include <talloc/talloc.h>
        <br>
        +#include <i18n/i18n.h>
        <br>
        +
        <br>
        +#include "grub2.h"
        <br>
        +#include "discover/parser-conf.h"
        <br>
        +#include "discover/parser.h"
        <br>
        +
        <br>
        +#define BLS_DIR "/loader/entries"
        <br>
        +
        <br>
        +struct bls_state {
        <br>
        +     struct discover_boot_option *opt;
        <br>
        +     struct grub2_script *script;
        <br>
        +     const char *filename;
        <br>
        +     const char *title;
        <br>
        +     const char *version;
        <br>
        +     const char *machine_id;
        <br>
        +     const char *image;
        <br>
        +     const char *initrd;
        <br>
        +     const char *dtb;
        <br>
        +};
        <br>
        +
        <br>
        +static void bls_process_pair(struct conf_context *conf, const
        char *name,
        <br>
        +                          char *value)
        <br>
        +{
        <br>
        +     struct bls_state *state = conf->parser_info;
        <br>
        +     struct discover_boot_option *opt = state->opt;
        <br>
        +     struct boot_option *option = opt->option;
        <br>
        +     const char *boot_args;
        <br>
        +
        <br>
        +     if (streq(name, "title")) {
        <br>
        +             state->title = talloc_strdup(state, value);
        <br>
        +             return;
        <br>
        +     }
        <br>
        +
        <br>
        +     if (streq(name, "version")) {
        <br>
        +             state->version = talloc_strdup(state, value);
        <br>
        +             return;
        <br>
        +     }
        <br>
        +
        <br>
        +     if (streq(name, "machine-id")) {
        <br>
        +             state->machine_id = talloc_strdup(state,
        value);
        <br>
        +             return;
        <br>
        +     }
        <br>
        +
        <br>
        +     if (streq(name, "linux")) {
        <br>
        +             state->image = talloc_strdup(state, value);
        <br>
        +             return;
        <br>
        +     }
        <br>
        +
        <br>
        +     if (streq(name, "initrd")) {
        <br>
        +             state->initrd = talloc_strdup(state, value);
        <br>
        +             return;
        <br>
        +     }
        <br>
        +
        <br>
        +     if (streq(name, "devicetree")) {
        <br>
        +             state->dtb = talloc_strdup(state, value);
        <br>
        +             return;
        <br>
        +     }
        <br>
        +
        <br>
        +     if (streq(name, "options")) {
        <br>
        +             if (value[0] == '$') {
        <br>
        +                     boot_args =
        script_env_get(state->script, value + 1);
        <br>
        +                     if (!boot_args)
        <br>
        +                             return;
        <br>
        +
        <br>
        +                     option->boot_args = talloc_strdup(opt,
        boot_args);
        <br>
        +             } else {
        <br>
        +                     option->boot_args = talloc_strdup(opt,
        value);
        <br>
        +             }
        <br>
        +             return;
        <br>
        +     }
        <br>
        +}
        <br>
        +
        <br>
        +static void bls_finish(struct conf_context *conf)
        <br>
        +{
        <br>
        +     struct discover_device *dev = conf->dc->device;
        <br>
        +     struct bls_state *state = conf->parser_info;
        <br>
        +     struct discover_context *dc = conf->dc;
        <br>
        +     struct discover_boot_option *opt = state->opt;
        <br>
        +     struct boot_option *option = opt->option;
        <br>
        +     const char *root;
        <br>
        +
        <br>
        +     if (!state->image) {
        <br>
        +             device_handler_status_dev_info(dc->handler,
        dc->device,
        <br>
        +                                            _("linux field not
        found in %s"),
        <br>
        +                                           
        state->filename);
        <br>
        +             return;
        <br>
        +     }
        <br>
        +
        <br>
        +     option->id = talloc_asprintf(option, "%s#%s",
        dev->device->id,
        <br>
        +                                  state->image);
        <br>
        +
        <br>
        +     if (state->title)
        <br>
        +             option->name = talloc_strdup(option,
        state->title);
        <br>
        +     else if (state->machine_id &&
        state->version)
        <br>
        +             option->name = talloc_asprintf(option, "%s %s",
        <br>
        +                                           
        state->machine_id,
        <br>
        +                                            state->version);
        <br>
        +     else if (state->version)
        <br>
        +             option->name = talloc_strdup(option,
        state->version);
        <br>
        +     else
        <br>
        +             option->name = talloc_strdup(option,
        option->id);
        <br>
        +
        <br>
        +     root = script_env_get(state->script, "root");
        <br>
        +
        <br>
        +     opt->boot_image = create_grub2_resource(opt,
        conf->dc->device,
        <br>
        +                                             root,
        state->image);
        <br>
        +
        <br>
        +     if (state->initrd)
        <br>
        +             opt->initrd = create_grub2_resource(opt,
        conf->dc->device,
        <br>
        +                                                 root,
        state->initrd);
        <br>
        +
        <br>
        +     if (state->dtb)
        <br>
        +             opt->dtb = create_grub2_resource(opt,
        conf->dc->device,
        <br>
        +                                              root,
        state->dtb);
        <br>
        +     discover_context_add_boot_option(dc, opt);
        <br>
        +
        <br>
        +     device_handler_status_dev_info(dc->handler,
        dc->device,
        <br>
        +                                    _("Created menu entry from
        BLS file %s"),
        <br>
        +                                    state->filename);
        <br>
        +}
        <br>
        +
        <br>
        +static int bls_filter(const struct dirent *ent)
        <br>
        +{
        <br>
        +     int offset = strlen(ent->d_name) - strlen(".conf");
        <br>
        +
        <br>
        +     if (offset < 0)
        <br>
        +             return 0;
        <br>
        +
        <br>
        +     return strncmp(ent->d_name + offset, ".conf",
        strlen(".conf")) == 0;
        <br>
        +}
        <br>
        +
        <br>
        +static int bls_sort(const struct dirent **ent_a, const struct
        dirent **ent_b)
        <br>
        +{
        <br>
        +     return strverscmp((*ent_b)->d_name,
        (*ent_a)->d_name);
        <br>
        +}
        <br>
        +
        <br>
        +int builtin_blscfg(struct grub2_script *script,
        <br>
        +             void *data __attribute__((unused)),
        <br>
        +             int argc __attribute__((unused)),
        <br>
        +             char *argv[] __attribute__((unused)));
        <br>
        +
        <br>
        +int builtin_blscfg(struct grub2_script *script,
        <br>
        +             void *data __attribute__((unused)),
        <br>
        +             int argc __attribute__((unused)),
        <br>
        +             char *argv[] __attribute__((unused)))
        <br>
        +{
        <br>
        +     struct discover_context *dc = script->ctx;
        <br>
        +     struct dirent **bls_entries;
        <br>
        +     struct conf_context *conf;
        <br>
        +     struct bls_state *state;
        <br>
        +     char *buf, *filename;
        <br>
        +     int n, len, rc = -1;
        <br>
        +
        <br>
        +     conf = talloc_zero(dc, struct conf_context);
        <br>
        +     if (!conf)
        <br>
        +             return rc;
        <br>
        +
        <br>
        +     conf->dc = dc;
        <br>
        +     conf->get_pair = conf_get_pair_space;
        <br>
        +     conf->process_pair = bls_process_pair;
        <br>
        +     conf->finish = bls_finish;
        <br>
        +
        <br>
        +     n = parser_scandir(dc, BLS_DIR, &bls_entries,
        bls_filter, bls_sort);
        <br>
        +     if (n <= 0)
        <br>
        +             goto err;
        <br>
        +
        <br>
        +     while (n--) {
        <br>
        +             filename = talloc_asprintf(dc, BLS_DIR"/%s",
        <br>
        +                                       
        bls_entries[n]->d_name);
        <br>
        +             if (!filename)
        <br>
        +                     break;
        <br>
        +
        <br>
        +             state = talloc_zero(conf, struct bls_state);
        <br>
        +             if (!state)
        <br>
        +                     break;
        <br>
        +
        <br>
        +             state->opt = discover_boot_option_create(dc,
        dc->device);
        <br>
        +             if (!state->opt)
        <br>
        +                     break;
        <br>
        +
        <br>
        +             state->script = script;
        <br>
        +             state->filename = filename;
        <br>
        +             conf->parser_info = state;
        <br>
        +
        <br>
        +             rc = parser_request_file(dc, dc->device,
        filename, &buf, &len);
        <br>
        +             if (rc)
        <br>
        +                     break;
        <br>
        +
        <br>
        +             conf_parse_buf(conf, buf, len);
        <br>
        +
        <br>
        +             talloc_free(buf);
        <br>
        +             talloc_free(state);
        <br>
        +             talloc_free(filename);
        <br>
        +             free(bls_entries[n]);
        <br>
        +     }
        <br>
        +
        <br>
        +     if (n > 0) {
        <br>
        +             device_handler_status_dev_info(dc->handler,
        dc->device,
        <br>
        +                                            _("Scanning %s
        failed"),
        <br>
        +                                            BLS_DIR);
        <br>
        +             do {
        <br>
        +                     free(bls_entries[n]);
        <br>
        +             } while (n-- > 0);
        <br>
        +     }
        <br>
        +
        <br>
        +     free(bls_entries);
        <br>
        +err:
        <br>
        +     talloc_free(conf);
        <br>
        +     return rc;
        <br>
        +}
        <br>
        diff --git a/discover/grub2/builtins.c
        b/discover/grub2/builtins.c
        <br>
        index c16b6390225a..e42821a64a9a 100644
        <br>
        --- a/discover/grub2/builtins.c
        <br>
        +++ b/discover/grub2/builtins.c
        <br>
        @@ -330,7 +330,10 @@ extern int builtin_load_env(struct
        grub2_script *script,
        <br>
          int builtin_save_env(struct grub2_script *script,
        <br>
                      void *data __attribute__((unused)),
        <br>
                      int argc, char *argv[]);
        <br>
        -
        <br>
        +int builtin_blscfg(struct grub2_script *script,
        <br>
        +             void *data __attribute__((unused)),
        <br>
        +             int argc __attribute__((unused)),
        <br>
        +             char *argv[] __attribute__((unused)));
        <br>
        <br>
          static struct {
        <br>
              const char *name;
        <br>
        @@ -380,6 +383,10 @@ static struct {
        <br>
                      .name = "save_env",
        <br>
                      .fn = builtin_save_env,
        <br>
              },
        <br>
        +     {
        <br>
        +             .name = "blscfg",
        <br>
        +             .fn = builtin_blscfg,
        <br>
        +     }
        <br>
          };
        <br>
        <br>
          static const char *nops[] = {
        <br>
        diff --git a/discover/parser.c b/discover/parser.c
        <br>
        index 5598f963e236..9fe1925d94c4 100644
        <br>
        --- a/discover/parser.c
        <br>
        +++ b/discover/parser.c
        <br>
        @@ -128,6 +128,22 @@ out:
        <br>
              return -1;
        <br>
          }
        <br>
        <br>
        +int parser_scandir(struct discover_context *ctx, const char
        *dirname,
        <br>
        +                struct dirent ***files, int (*filter)(const
        struct dirent *),
        <br>
        +                int (*comp)(const struct dirent **, const
        struct dirent **))
        <br>
        +{
        <br>
        +     char *path;
        <br>
        +     int n;
        <br>
        +
        <br>
        +     path = talloc_asprintf(ctx, "%s%s",
        ctx->device->mount_path, dirname);
        <br>
        +     if (!path)
        <br>
        +             return -1;
        <br>
        +
        <br>
        +     n = scandir(path, files, filter, comp);
        <br>
        +     talloc_free(path);
        <br>
        +     return n;
        <br>
        +}
        <br>
        +
        <br>
          void iterate_parsers(struct discover_context *ctx)
        <br>
          {
        <br>
              struct p_item* i;
        <br>
        diff --git a/discover/parser.h b/discover/parser.h
        <br>
        index fc165c5aeda4..bff52e30d09f 100644
        <br>
        --- a/discover/parser.h
        <br>
        +++ b/discover/parser.h
        <br>
        @@ -5,6 +5,7 @@
        <br>
          #include <sys/types.h>
        <br>
          #include <sys/stat.h>
        <br>
          #include <unistd.h>
        <br>
        +#include <dirent.h>
        <br>
        <br>
          #include "device-handler.h"
        <br>
        <br>
        @@ -76,5 +77,12 @@ int parser_request_url(struct
        discover_context *ctx, struct pb_url *url,
        <br>
          int parser_stat_path(struct discover_context *ctx,
        <br>
                      struct discover_device *dev, const char *path,
        <br>
                      struct stat *statbuf);
        <br>
        +/* Function used to list the files on a directory. The dirname
        should
        <br>
        + * be relative to the discover context device mount path. It
        returns
        <br>
        + * the number of files returned in files or a negative value on
        error.
        <br>
        + */
        <br>
        +int parser_scandir(struct discover_context *ctx, const char
        *dirname,
        <br>
        +                struct dirent ***files, int (*filter)(const
        struct dirent *),
        <br>
        +                int (*comp)(const struct dirent **, const
        struct dirent **));
        <br>
        <br>
          #endif /* _PARSER_H */
        <br>
        diff --git a/test/parser/Makefile.am b/test/parser/Makefile.am
        <br>
        index a0795dbcf899..b943408c4942 100644
        <br>
        --- a/test/parser/Makefile.am
        <br>
        +++ b/test/parser/Makefile.am
        <br>
        @@ -40,6 +40,9 @@ parser_TESTS = \
        <br>
              test/parser/test-grub2-parser-error \
        <br>
              test/parser/test-grub2-test-file-ops \
        <br>
              test/parser/test-grub2-single-yocto \
        <br>
        +     test/parser/test-grub2-blscfg-multiple-bls \
        <br>
        +     test/parser/test-grub2-blscfg-opts-config \
        <br>
        +     test/parser/test-grub2-blscfg-opts-grubenv \
        <br>
              test/parser/test-kboot-single \
        <br>
              test/parser/test-yaboot-empty \
        <br>
              test/parser/test-yaboot-single \
        <br>
        diff --git a/test/parser/test-grub2-blscfg-multiple-bls.c
        b/test/parser/test-grub2-blscfg-multiple-bls.c
        <br>
        new file mode 100644
        <br>
        index 000000000000..8fd218c371e8
        <br>
        --- /dev/null
        <br>
        +++ b/test/parser/test-grub2-blscfg-multiple-bls.c
        <br>
        @@ -0,0 +1,44 @@
        <br>
        +#include "parser-test.h"
        <br>
        +
        <br>
        +#if 0 /* PARSER_EMBEDDED_CONFIG */
        <br>
        +blscfg
        <br>
        +#endif
        <br>
        +
        <br>
        +void run_test(struct parser_test *test)
        <br>
        +{
        <br>
        +     struct discover_boot_option *opt;
        <br>
        +     struct discover_context *ctx;
        <br>
        +
        <br>
        +     test_add_file_string(test, test->ctx->device,
        <br>
        +                         
"/loader/entries/6c063c8e48904f2684abde8eea303f41-4.15.2-302.fc28.x86_64.conf",<br>
        +                          "title Fedora
        (4.15.2-302.fc28.x86_64) 28 (Twenty Eight)\n"
        <br>
        +                          "linux
        /vmlinuz-4.15.2-302.fc28.x86_64\n"
        <br>
        +                          "initrd
        /initramfs-4.15.2-302.fc28.x86_64.img\n"
        <br>
        +                          "options root=/dev/mapper/fedora-root
        ro rd.lvm.lv=fedora/root\n\n");
        <br>
        +
        <br>
        +     test_add_file_string(test, test->ctx->device,
        <br>
        +                         
"/loader/entries/6c063c8e48904f2684abde8eea303f41-4.14.18-300.fc28.x86_64.conf",<br>
        +                          "title Fedora
        (4.14.18-300.fc28.x86_64) 28 (Twenty Eight)\n"
        <br>
        +                          "linux
        /vmlinuz-4.14.18-300.fc28.x86_64\n"
        <br>
        +                          "initrd
        /initramfs-4.14.18-300.fc28.x86_64.img\n"
        <br>
        +                          "options root=/dev/mapper/fedora-root
        ro rd.lvm.lv=fedora/root\n");
        <br>
        +
        <br>
        +     test_read_conf_embedded(test, "/boot/grub2/grub.cfg");
        <br>
        +
        <br>
        +     test_run_parser(test, "grub2");
        <br>
        +
        <br>
        +     ctx = test->ctx;
        <br>
        +
        <br>
        +     check_boot_option_count(ctx, 2);
        <br>
        +     opt = get_boot_option(ctx, 0);
        <br>
        +
        <br>
        +     check_name(opt, "Fedora (4.15.2-302.fc28.x86_64) 28
        (Twenty Eight)");
        <br>
        +     check_resolved_local_resource(opt->boot_image,
        ctx->device,
        <br>
        +                     "/vmlinuz-4.15.2-302.fc28.x86_64");
        <br>
        +
        <br>
        +     opt = get_boot_option(ctx, 1);
        <br>
        +
        <br>
        +     check_name(opt, "Fedora (4.14.18-300.fc28.x86_64) 28
        (Twenty Eight)");
        <br>
        +     check_resolved_local_resource(opt->initrd,
        ctx->device,
        <br>
        +                     "/initramfs-4.14.18-300.fc28.x86_64.img");
        <br>
        +}
        <br>
        diff --git a/test/parser/test-grub2-blscfg-opts-config.c
        b/test/parser/test-grub2-blscfg-opts-config.c
        <br>
        new file mode 100644
        <br>
        index 000000000000..856aae2adf5f
        <br>
        --- /dev/null
        <br>
        +++ b/test/parser/test-grub2-blscfg-opts-config.c
        <br>
        @@ -0,0 +1,29 @@
        <br>
        +#include "parser-test.h"
        <br>
        +
        <br>
        +#if 0 /* PARSER_EMBEDDED_CONFIG */
        <br>
        +set kernelopts=root=/dev/mapper/fedora-root ro
        rd.lvm.lv=fedora/root
        <br>
        +blscfg
        <br>
        +#endif
        <br>
        +
        <br>
        +void run_test(struct parser_test *test)
        <br>
        +{
        <br>
        +     struct discover_boot_option *opt;
        <br>
        +     struct discover_context *ctx;
        <br>
        +
        <br>
        +     test_add_file_string(test, test->ctx->device,
        <br>
        +                         
"/loader/entries/6c063c8e48904f2684abde8eea303f41-4.15.2-302.fc28.x86_64.conf",<br>
        +                          "title Fedora
        (4.15.2-302.fc28.x86_64) 28 (Twenty Eight)\n"
        <br>
        +                          "linux
        /vmlinuz-4.15.2-302.fc28.x86_64\n"
        <br>
        +                          "initrd
        /initramfs-4.15.2-302.fc28.x86_64.img\n"
        <br>
        +                          "options $kernelopts\n");
        <br>
        +
        <br>
        +     test_read_conf_embedded(test, "/boot/grub2/grub.cfg");
        <br>
        +
        <br>
        +     test_run_parser(test, "grub2");
        <br>
        +
        <br>
        +     ctx = test->ctx;
        <br>
        +
        <br>
        +     opt = get_boot_option(ctx, 0);
        <br>
        +
        <br>
        +     check_args(opt, "root=/dev/mapper/fedora-root ro
        rd.lvm.lv=fedora/root");
        <br>
        +}
        <br>
        diff --git a/test/parser/test-grub2-blscfg-opts-grubenv.c
        b/test/parser/test-grub2-blscfg-opts-grubenv.c
        <br>
        new file mode 100644
        <br>
        index 000000000000..c77c589b7707
        <br>
        --- /dev/null
        <br>
        +++ b/test/parser/test-grub2-blscfg-opts-grubenv.c
        <br>
        @@ -0,0 +1,34 @@
        <br>
        +#include "parser-test.h"
        <br>
        +
        <br>
        +#if 0 /* PARSER_EMBEDDED_CONFIG */
        <br>
        +load_env
        <br>
        +blscfg
        <br>
        +#endif
        <br>
        +
        <br>
        +void run_test(struct parser_test *test)
        <br>
        +{
        <br>
        +     struct discover_boot_option *opt;
        <br>
        +     struct discover_context *ctx;
        <br>
        +
        <br>
        +     test_add_file_string(test, test->ctx->device,
        <br>
        +                          "/boot/grub2/grubenv",
        <br>
        +                          "# GRUB Environment Block\n"
        <br>
        +                         
        "kernelopts=root=/dev/mapper/fedora-root ro
        rd.lvm.lv=fedora/root\n");
        <br>
        +
        <br>
        +     test_add_file_string(test, test->ctx->device,
        <br>
        +                         
"/loader/entries/6c063c8e48904f2684abde8eea303f41-4.15.2-302.fc28.x86_64.conf",<br>
        +                          "title Fedora
        (4.15.2-302.fc28.x86_64) 28 (Twenty Eight)\n"
        <br>
        +                          "linux
        /vmlinuz-4.15.2-302.fc28.x86_64\n"
        <br>
        +                          "initrd
        /initramfs-4.15.2-302.fc28.x86_64.img\n"
        <br>
        +                          "options $kernelopts\n");
        <br>
        +
        <br>
        +     test_read_conf_embedded(test, "/boot/grub2/grub.cfg");
        <br>
        +
        <br>
        +     test_run_parser(test, "grub2");
        <br>
        +
        <br>
        +     ctx = test->ctx;
        <br>
        +
        <br>
        +     opt = get_boot_option(ctx, 0);
        <br>
        +
        <br>
        +     check_args(opt, "root=/dev/mapper/fedora-root ro
        rd.lvm.lv=fedora/root");
        <br>
        +}
        <br>
        diff --git a/test/parser/utils.c b/test/parser/utils.c
        <br>
        index 8900bd72bebd..683bba7d0379 100644
        <br>
        --- a/test/parser/utils.c
        <br>
        +++ b/test/parser/utils.c
        <br>
        @@ -309,6 +309,65 @@ int parser_replace_file(struct
        discover_context *ctx,
        <br>
              return 0;
        <br>
          }
        <br>
        <br>
        +int parser_scandir(struct discover_context *ctx, const char
        *dirname,
        <br>
        +                struct dirent ***files, int (*filter)(const
        struct dirent *)
        <br>
        +                __attribute__((unused)),
        <br>
        +                int (*comp)(const struct dirent **, const
        struct dirent **)
        <br>
        +                __attribute__((unused)))
        <br>
        +{
        <br>
        +     struct parser_test *test = ctx->test_data;
        <br>
        +     struct test_file *f;
        <br>
        +     char *filename;
        <br>
        +     struct dirent **dirents = NULL, **new_dirents;
        <br>
        +     int n = 0, namelen;
        <br>
        +
        <br>
        +     list_for_each_entry(&test->files, f, list) {
        <br>
        +             if (f->dev != ctx->device)
        <br>
        +                     continue;
        <br>
        +
        <br>
        +             filename = strrchr(f->name, '/');
        <br>
        +             if (!filename)
        <br>
        +                     continue;
        <br>
        +
        <br>
        +             namelen = strlen(filename);
        <br>
        +
        <br>
        +             if (strncmp(f->name, dirname,
        strlen(f->name) - namelen))
        <br>
        +                     continue;
        <br>
        +
        <br>
        +             if (!dirents) {
        <br>
        +                     dirents = malloc(sizeof(struct dirent *));
        <br>
        +             } else {
        <br>
        +                     new_dirents = realloc(dirents,
        sizeof(struct dirent *)
        <br>
        +                                           * (n + 1));
        <br>
        +                     if (!new_dirents)
        <br>
        +                             goto err_cleanup;
        <br>
        +
        <br>
        +                     dirents = new_dirents;
        <br>
        +             }
        <br>
        +
        <br>
        +             dirents[n] = malloc(sizeof(struct dirent) +
        namelen + 1);
        <br>
        +
        <br>
        +             if (!dirents[n])
        <br>
        +                     goto err_cleanup;
        <br>
        +
        <br>
        +             strcpy(dirents[n]->d_name, filename + 1);
        <br>
        +             n++;
        <br>
        +     }
        <br>
        +
        <br>
        +     *files = dirents;
        <br>
        +
        <br>
        +     return n;
        <br>
        +
        <br>
        +err_cleanup:
        <br>
        +     do {
        <br>
        +             free(dirents[n]);
        <br>
        +     } while (n-- > 0);
        <br>
        +
        <br>
        +     free(dirents);
        <br>
        +
        <br>
        +     return -1;
        <br>
        +}
        <br>
        +
        <br>
          struct load_url_result *load_url_async(void *ctx, struct
        pb_url *url,
        <br>
                      load_url_complete async_cb, void *async_data,
        <br>
                      waiter_cb stdout_cb, void *stdout_data)
        <br>
      </blockquote>
      <br>
      _______________________________________________
      <br>
      Petitboot mailing list
      <br>
      <a class="moz-txt-link-abbreviated" href="mailto:Petitboot@lists.ozlabs.org">Petitboot@lists.ozlabs.org</a>
      <br>
      <a class="moz-txt-link-freetext" href="https://lists.ozlabs.org/listinfo/petitboot">https://lists.ozlabs.org/listinfo/petitboot</a>
      <br>
    </blockquote>
    <br>
  </body>
</html>