Gregory Lee Bartholomew
2019-May-24 22:33 UTC
[syslinux] [PATCH] (vesa)menu.c32: Add support for BLS
Modern distributions are moving toward a common boot scheme called "The
Boot
Loader Specification". This patch enables syslinux's (vesa)menu.c32
modules to
parse the drop-in files that are defined by this new specification.
Link to The Boot Loader Specification:
https://systemd.io/BOOT_LOADER_SPECIFICATION
Link to demonstration bootdisk image (82MB gzipped):
https://drive.google.com/uc?export=download&id=1e4tQU3oM1kPOVDG3pjRGBpOXTwdeuzRx
Link to bash script used to create above bootdisk image (1.3KB gzipped):
https://drive.google.com/uc?export=download&id=1YzZYBCWFhhMtUJotzR7MLiQL6XTH_19Z
To test the bootdisk image in BIOS mode you can use:
$ qemu-system-x86_64 -machine accel=kvm -m 1024 -drive \
file=bootdisk.img,format=raw
To test the bootdisk image in UEFI mode you can use:
$ cp /usr/share/edk2/ovmf/OVMF_VARS.fd OVMF_VARS.fd
$ qemu-system-x86_64 -machine accel=kvm -m 1024 -drive \
if=pflash,format=raw,unit=0,file=/usr/share/edk2/ovmf/OVMF_CODE.fd,readonly=on \
-drive if=pflash,format=raw,unit=1,file=OVMF_VARS.fd -drive \
file=bootdisk.img,format=raw
Signed-off-by: Gregory Lee Bartholomew <gregory.lee.bartholomew at
gmail.com>
---
com32/menu/readconfig.c | 340 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 340 insertions(+)
diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c
index a433fadb..627596d8 100644
--- a/com32/menu/readconfig.c
+++ b/com32/menu/readconfig.c
@@ -21,11 +21,17 @@
#include <inttypes.h>
#include <colortbl.h>
#include <com32.h>
+#include <dirent.h>
#include <syslinux/adv.h>
#include <syslinux/config.h>
#include "menu.h"
+/* BLS entry global settings */
+#define BLS_CHUNK 16
+int bls_version_places = 3;
+char *bls_sort_by = "machine-id version title";
+
/* Empty refstring */
const char *empty_string;
@@ -1060,6 +1066,337 @@ do_include:
}
}
+/*
+ * https://systemd.io/BOOT_LOADER_SPECIFICATION
+ * #type-1-boot-loader-specification-entries
+ */
+struct blsdata {
+ const char *title;
+ const char *version;
+ char *version0; /* version string padded with zeros */
+ const char *machine_id;
+ const char *linux_;
+ const char *initrd;
+ const char *efi;
+ char *options;
+ const char *devicetree;
+ const char *architecture;
+ char *sort_field; /* used internally for sorting */
+ const char *filename;
+};
+
+static void clear_bls_data(struct blsdata *bd)
+{
+ refstr_put(bd->title);
+ refstr_put(bd->version);
+ free(bd->version0);
+ refstr_put(bd->machine_id);
+ refstr_put(bd->linux_);
+ refstr_put(bd->initrd);
+ refstr_put(bd->efi);
+ free(bd->options);
+ refstr_put(bd->devicetree);
+ refstr_put(bd->architecture);
+ free(bd->sort_field);
+ refstr_put(bd->filename);
+
+ memset(bd, 0, sizeof *bd);
+}
+
+/*
+ * Pads the numeric fields of a version string with zeros.
+ * Used to get kernel versions to sort a little better.
+ */
+static char *padver(const char *version) {
+ int i, j, d, len = strlen(version);
+ char *bwd = NULL, *fwd = NULL, *tmp;
+
+ bwd = malloc(len + 1);
+ if (!bwd)
+ goto nomem;
+
+ d = (version[len-1] >= '0' && version[len-1] <=
'9') ?
+ bls_version_places : 0;
+ for (i = len, j = 0; j <= len+1; i--, j++) {
+ if (i < 0 || version[i] == '.' || version[i] == '-')
{
+ if (d > 0) {
+ len += d;
+ if ((tmp = realloc(bwd, len))) {
+ bwd = tmp;
+ } else {
+ goto nomem;
+ }
+ while (d--) {
+ bwd[j++] = '0';
+ }
+ }
+ d = bls_version_places;
+ } else if (version[i] >= '0' && version[i] <=
'9') {
+ d--;
+ } else if (version[i]) {
+ d = 0;
+ }
+ if (i >= 0) {
+ bwd[j] = version[i];
+ }
+ }
+
+ fwd = malloc(len + 1);
+ if (!fwd)
+ goto nomem;
+
+ tmp = bwd;
+ for (i = len; i >= 0; i--) {
+ fwd[i] = *tmp;
+ tmp++;
+ }
+ free(bwd);
+
+ return fwd;
+
+nomem:
+ dprintf("Out of memory error!\n");
+ free(bwd);
+ free(fwd);
+ return NULL;
+}
+
+static int parse_bls1_file(struct blsdata *bd, const char *filename)
+{
+ FILE *f = NULL;
+ char line[MAX_LINE], *p;
+ char *sort_field;
+
+ dprintf("Opening bls entry: %s ", filename);
+
+ f = fopen(filename, "r");
+ dprintf("%s\n", f ? "ok" : "failed");
+
+ if (!f)
+ return -1;
+
+ refstr_put(bd->filename);
+ bd->filename = refstrdup(filename);
+
+ while (fgets(line, sizeof line, f)) {
+ p = strchr(line, '\r');
+ if (p)
+ *p = '\0';
+ p = strchr(line, '\n');
+ if (p)
+ *p = '\0';
+
+ p = skipspace(line);
+
+ if (looking_at(p, "title")) {
+ refstr_put(bd->title);
+ bd->title = refstrdup(skipspace(p + 5));
+ } else if (looking_at(p, "version")) {
+ refstr_put(bd->version);
+ bd->version = refstrdup(skipspace(p + 7));
+ bd->version0 = padver(bd->version);
+ } else if (looking_at(p, "machine-id")) {
+ refstr_put(bd->machine_id);
+ bd->machine_id = refstrdup(skipspace(p + 10));
+ } else if (looking_at(p, "linux")) {
+ refstr_put(bd->linux_);
+ bd->linux_ = refstrdup(skipspace(p + 5));
+ } else if (looking_at(p, "initrd")) {
+ refstr_put(bd->initrd);
+ bd->initrd = refstrdup(skipspace(p + 6));
+ } else if (looking_at(p, "efi")) {
+ refstr_put(bd->efi);
+ bd->efi = refstrdup(skipspace(p + 3));
+ } else if (looking_at(p, "options")) {
+ /* The "options" keyword can be specified multiple times
*/
+ int len = bd->options ? strlen(bd->options) : 0;
+ int xlen;
+ p = skipspace(p + 7);
+ xlen = strlen(p);
+ if (len && xlen) {
+ /* Grab one space char from the file */
+ p--;
+ xlen++;
+ }
+ bd->options = realloc(bd->options, len + xlen + 1);
+ memcpy(bd->options + len, p, xlen + 1);
+ } else if (looking_at(p, "devicetree")) {
+ refstr_put(bd->devicetree);
+ bd->devicetree = refstrdup(skipspace(p + 10));
+ } else if (looking_at(p, "architecture")) {
+ refstr_put(bd->architecture);
+ bd->architecture = refstrdup(skipspace(p + 12));
+ }
+ }
+
+ fclose(f);
+
+ p = get_word(bls_sort_by, &sort_field);
+ while (sort_field && *sort_field != '\0') {
+ const char *sf = NULL;
+
+ if (looking_at(sort_field, "title")) {
+ sf = bd->title;
+ } else if (looking_at(sort_field, "version")) {
+ sf = bd->version0;
+ } else if (looking_at(sort_field, "machine-id")) {
+ sf = bd->machine_id;
+ }
+
+ if (sf) {
+ bd->sort_field = realloc(
+ bd->sort_field,
+ strlen(bd->sort_field) + strlen(sf) + 1
+ );
+ strcat(bd->sort_field, sf);
+ }
+ p = get_word(skipspace(p), &sort_field);
+ }
+
+ return (bd->linux_ || bd->efi) ? 0 : -1;
+}
+
+static int compare_blsdata(const void *p_bd1, const void *p_bd2)
+{
+ const struct blsdata *bd1 = *(const struct blsdata **)p_bd1;
+ const struct blsdata *bd2 = *(const struct blsdata **)p_bd2;
+
+ const char *a = NULL, *b = NULL;
+
+ if (bd1->sort_field && bd2->sort_field) {
+ a = bd1->sort_field;
+ b = bd2->sort_field;
+ } else if (bd1->title && bd2->title) {
+ a = bd1->title;
+ b = bd2->title;
+ } else if (bd1->linux_ && bd2->linux_) {
+ a = bd1->linux_;
+ b = bd2->linux_;
+ } else if (bd1->efi && bd2->efi) {
+ a = bd1->efi;
+ b = bd2->efi;
+ } else {
+ /* We should never get here */
+ return 0;
+ }
+
+ return strcmp(a, b);
+}
+
+static int parse_bls1_dir(const char *dirname)
+{
+ DIR *d = NULL;
+ char *filename = NULL;
+ struct dirent *de = NULL;
+ struct blsdata *nbd = NULL, **bdx = NULL;
+ int i, n_bdx = 0, n_bd = 0;
+ int rv = -1, fn_len, dn_len;
+ struct menu *m = current_menu;
+
+ if (!*dirname)
+ return -1;
+
+ dprintf("Opening bls entries directory %s ", dirname);
+
+ d = opendir(dirname);
+ dprintf("%s\n", d ? "ok" : "failed");
+
+ if (!d)
+ return -1;
+
+ dn_len = strlen(dirname);
+
+ /* Process up to 128 files */
+ /* https://wiki.syslinux.org/wiki/
+ index.php?title=Syslinux_1_Changelog#Changes_in_1.37 */
+ while ((de = readdir(d)) != NULL && n_bd < 128) {
+ if (de->d_type != DT_REG)
+ continue;
+
+ fn_len = strlen(de->d_name);
+ if (strcmp(de->d_name+(fn_len-5), ".conf"))
+ continue;
+
+ if (!(filename = malloc(dn_len + 1 + fn_len + 1)))
+ goto nomem;
+
+ strcpy(filename, dirname);
+ strcat(filename, "/");
+ strcat(filename, de->d_name);
+
+ if (n_bd >= n_bdx) {
+ struct blsdata **nbdx;
+
+ nbdx = realloc(bdx, (n_bdx + BLS_CHUNK) * sizeof *bdx);
+ if (!nbdx)
+ goto nomem;
+
+ bdx = nbdx;
+ n_bdx += BLS_CHUNK;
+ }
+
+ nbd = malloc(sizeof(struct blsdata));
+ if (!nbd)
+ goto nomem;
+
+ memset(nbd, 0, sizeof *nbd);
+ if (parse_bls1_file(nbd, filename) == 0) {
+ bdx[n_bd++] = nbd;
+ rv = 0;
+ } else {
+ clear_bls_data(nbd);
+ free(nbd);
+ }
+
+ free(filename);
+ }
+
+ closedir(d);
+
+ qsort(bdx, n_bd, sizeof *bdx, compare_blsdata);
+
+ /* For each of the BLS entries,
+ do essentially the same as the looking_at(p, "label")
+ clause of the parse_config_file() function */
+ for (i = 0; i < n_bd; i++) {
+ record(m, &ld, append);
+
+ char *label = malloc(16);
+ snprintf(label, 16, "BLS%03d", i);
+ ld.label = refstrdup(label);
+ free(label);
+
+ ld.kernel = (bdx[i]->linux_) ? refstrdup(bdx[i]->linux_) : NULL;
+ ld.type = KT_LINUX;
+ ld.passwd = NULL;
+ ld.append = (bdx[i]->options) ? refstrdup(bdx[i]->options) :
NULL;
+ ld.initrd = (bdx[i]->initrd) ? refstrdup(bdx[i]->initrd) : NULL;
+ ld.menulabel = (bdx[i]->title) ? refstrdup(bdx[i]->title) : NULL;
+ ld.ipappend = ipappend;
+ ld.menudefault = ld.menuhide = ld.menuseparator +
ld.menudisabled = ld.menuindent = 0;
+
+ clear_bls_data(bdx[i]);
+ free(bdx[i]);
+ }
+
+ return rv;
+
+nomem:
+ dprintf("Out of memory error!\n");
+ free(filename);
+ for (i = 0; i < n_bd; i++) {
+ clear_bls_data(bdx[i]);
+ free(bdx[i]);
+ }
+ free(bdx);
+ clear_bls_data(nbd);
+ free(nbd);
+ if (d)
+ closedir(d);
+ return -1;
+}
+
static int parse_one_config(const char *filename)
{
FILE *f;
@@ -1067,6 +1404,9 @@ static int parse_one_config(const char *filename)
if (!strcmp(filename, "~"))
filename = syslinux_config_file();
+ if (!strncmp(filename, "bls1:", 5) || !strncmp(filename,
"BLS1:", 5))
+ return parse_bls1_dir(filename+5);
+
dprintf("Opening config file: %s ", filename);
f = fopen(filename, "r");
--
2.20.1
Sebastian Herbszt
2019-May-25 20:41 UTC
[syslinux] [PATCH] (vesa)menu.c32: Add support for BLS
Gregory Lee Bartholomew wrote:> Modern distributions are moving toward a common boot scheme called > "The Boot Loader Specification".Which distributions are using this yet?> This patch enables syslinux's > (vesa)menu.c32 modules to parse the drop-in files that are defined by > this new specification.Any reason why you don't try to implement this in syslinux core? <snip>> +static int parse_bls1_file(struct blsdata *bd, const char *filename) > +{ > + FILE *f = NULL; > + char line[MAX_LINE], *p; > + char *sort_field; > + > + dprintf("Opening bls entry: %s ", filename); > + > + f = fopen(filename, "r"); > + dprintf("%s\n", f ? "ok" : "failed"); > + > + if (!f) > + return -1; > + > + refstr_put(bd->filename); > + bd->filename = refstrdup(filename); > + > + while (fgets(line, sizeof line, f)) { > + p = strchr(line, '\r'); > + if (p) > + *p = '\0'; > + p = strchr(line, '\n'); > + if (p) > + *p = '\0'; > + > + p = skipspace(line); > + > + if (looking_at(p, "title")) { > + refstr_put(bd->title); > + bd->title = refstrdup(skipspace(p + 5)); > + } else if (looking_at(p, "version")) { > + refstr_put(bd->version); > + bd->version = refstrdup(skipspace(p + 7)); > + bd->version0 = padver(bd->version); > + } else if (looking_at(p, "machine-id")) { > + refstr_put(bd->machine_id); > + bd->machine_id = refstrdup(skipspace(p + 10)); > + } else if (looking_at(p, "linux")) { > + refstr_put(bd->linux_); > + bd->linux_ = refstrdup(skipspace(p + 5)); > + } else if (looking_at(p, "initrd")) { > + refstr_put(bd->initrd); > + bd->initrd = refstrdup(skipspace(p + 6));According to the specification "initrd" may appear more than once.> + } else if (looking_at(p, "efi")) { > + refstr_put(bd->efi); > + bd->efi = refstrdup(skipspace(p + 3)); > + } else if (looking_at(p, "options")) { > + /* The "options" keyword can be specified multiple times > */ > + int len = bd->options ? strlen(bd->options) : 0; > + int xlen; > + p = skipspace(p + 7); > + xlen = strlen(p); > + if (len && xlen) { > + /* Grab one space char from the file */ > + p--; > + xlen++; > + } > + bd->options = realloc(bd->options, len + xlen + 1); > + memcpy(bd->options + len, p, xlen + 1); > + } else if (looking_at(p, "devicetree")) { > + refstr_put(bd->devicetree); > + bd->devicetree = refstrdup(skipspace(p + 10)); > + } else if (looking_at(p, "architecture")) { > + refstr_put(bd->architecture); > + bd->architecture = refstrdup(skipspace(p + 12)); > + } > + } > + > + fclose(f); > + > + p = get_word(bls_sort_by, &sort_field); > + while (sort_field && *sort_field != '\0') { > + const char *sf = NULL; > + > + if (looking_at(sort_field, "title")) { > + sf = bd->title; > + } else if (looking_at(sort_field, "version")) { > + sf = bd->version0; > + } else if (looking_at(sort_field, "machine-id")) { > + sf = bd->machine_id; > + } > + > + if (sf) { > + bd->sort_field = realloc( > + bd->sort_field, > + strlen(bd->sort_field) + strlen(sf) + 1 > + ); > + strcat(bd->sort_field, sf); > + } > + p = get_word(skipspace(p), &sort_field); > + } > + > + return (bd->linux_ || bd->efi) ? 0 : -1; > +}<snip>> +static int parse_bls1_dir(const char *dirname) > +{ > + DIR *d = NULL; > + char *filename = NULL; > + struct dirent *de = NULL; > + struct blsdata *nbd = NULL, **bdx = NULL; > + int i, n_bdx = 0, n_bd = 0; > + int rv = -1, fn_len, dn_len; > + struct menu *m = current_menu; > + > + if (!*dirname) > + return -1; > + > + dprintf("Opening bls entries directory %s ", dirname); > + > + d = opendir(dirname); > + dprintf("%s\n", d ? "ok" : "failed"); > + > + if (!d) > + return -1; > + > + dn_len = strlen(dirname); > + > + /* Process up to 128 files */ > + /* https://wiki.syslinux.org/wiki/ > + index.php?title=Syslinux_1_Changelog#Changes_in_1.37 */ > + while ((de = readdir(d)) != NULL && n_bd < 128) {Are you sure this limit is still accurate? Sebastian
Gregory Lee Bartholomew
2019-May-25 20:46 UTC
[syslinux] [PATCH] (vesa)menu.c32: Add support for BLS
-- Gregory Lee Bartholomew PGP Key ID: 3B67510E On May 25, 2019 8:41:57 PM UTC, Sebastian Herbszt <herbszt at gmx.de> wrote:>Gregory Lee Bartholomew wrote: >> Modern distributions are moving toward a common boot scheme called >> "The Boot Loader Specification". > >Which distributions are using this yet?Fedora 30> >> This patch enables syslinux's >> (vesa)menu.c32 modules to parse the drop-in files that are defined by >> this new specification. > >Any reason why you don't try to implement this in syslinux core?Not sure what you mean by core, but I was trying to be minimally intrusive to the existing code.> ><snip> > >> +static int parse_bls1_file(struct blsdata *bd, const char *filename) >> +{ >> + FILE *f = NULL; >> + char line[MAX_LINE], *p; >> + char *sort_field; >> + >> + dprintf("Opening bls entry: %s ", filename); >> + >> + f = fopen(filename, "r"); >> + dprintf("%s\n", f ? "ok" : "failed"); >> + >> + if (!f) >> + return -1; >> + >> + refstr_put(bd->filename); >> + bd->filename = refstrdup(filename); >> + >> + while (fgets(line, sizeof line, f)) { >> + p = strchr(line, '\r'); >> + if (p) >> + *p = '\0'; >> + p = strchr(line, '\n'); >> + if (p) >> + *p = '\0'; >> + >> + p = skipspace(line); >> + >> + if (looking_at(p, "title")) { >> + refstr_put(bd->title); >> + bd->title = refstrdup(skipspace(p + 5)); >> + } else if (looking_at(p, "version")) { >> + refstr_put(bd->version); >> + bd->version = refstrdup(skipspace(p + 7)); >> + bd->version0 = padver(bd->version); >> + } else if (looking_at(p, "machine-id")) { >> + refstr_put(bd->machine_id); >> + bd->machine_id = refstrdup(skipspace(p + 10)); >> + } else if (looking_at(p, "linux")) { >> + refstr_put(bd->linux_); >> + bd->linux_ = refstrdup(skipspace(p + 5)); >> + } else if (looking_at(p, "initrd")) { >> + refstr_put(bd->initrd); >> + bd->initrd = refstrdup(skipspace(p + 6)); > >According to the specification "initrd" may appear more than once. > >> + } else if (looking_at(p, "efi")) { >> + refstr_put(bd->efi); >> + bd->efi = refstrdup(skipspace(p + 3)); >> + } else if (looking_at(p, "options")) { >> + /* The "options" keyword can be specified multiple times >> */ >> + int len = bd->options ? strlen(bd->options) : 0; >> + int xlen; >> + p = skipspace(p + 7); >> + xlen = strlen(p); >> + if (len && xlen) { >> + /* Grab one space char from the file */ >> + p--; >> + xlen++; >> + } >> + bd->options = realloc(bd->options, len + xlen + 1); >> + memcpy(bd->options + len, p, xlen + 1); >> + } else if (looking_at(p, "devicetree")) { >> + refstr_put(bd->devicetree); >> + bd->devicetree = refstrdup(skipspace(p + 10)); >> + } else if (looking_at(p, "architecture")) { >> + refstr_put(bd->architecture); >> + bd->architecture = refstrdup(skipspace(p + 12)); >> + } >> + } >> + >> + fclose(f); >> + >> + p = get_word(bls_sort_by, &sort_field); >> + while (sort_field && *sort_field != '\0') { >> + const char *sf = NULL; >> + >> + if (looking_at(sort_field, "title")) { >> + sf = bd->title; >> + } else if (looking_at(sort_field, "version")) { >> + sf = bd->version0; >> + } else if (looking_at(sort_field, "machine-id")) { >> + sf = bd->machine_id; >> + } >> + >> + if (sf) { >> + bd->sort_field = realloc( >> + bd->sort_field, >> + strlen(bd->sort_field) + strlen(sf) + 1 >> + ); >> + strcat(bd->sort_field, sf); >> + } >> + p = get_word(skipspace(p), &sort_field); >> + } >> + >> + return (bd->linux_ || bd->efi) ? 0 : -1; >> +} > ><snip> > >> +static int parse_bls1_dir(const char *dirname) >> +{ >> + DIR *d = NULL; >> + char *filename = NULL; >> + struct dirent *de = NULL; >> + struct blsdata *nbd = NULL, **bdx = NULL; >> + int i, n_bdx = 0, n_bd = 0; >> + int rv = -1, fn_len, dn_len; >> + struct menu *m = current_menu; >> + >> + if (!*dirname) >> + return -1; >> + >> + dprintf("Opening bls entries directory %s ", dirname); >> + >> + d = opendir(dirname); >> + dprintf("%s\n", d ? "ok" : "failed"); >> + >> + if (!d) >> + return -1; >> + >> + dn_len = strlen(dirname); >> + >> + /* Process up to 128 files */ >> + /* https://wiki.syslinux.org/wiki/ >> + index.php?title=Syslinux_1_Changelog#Changes_in_1.37 */ >> + while ((de = readdir(d)) != NULL && n_bd < 128) { > >Are you sure this limit is still accurate? > >Sebastian
Gregory Bartholomew
2019-May-25 21:34 UTC
[syslinux] [PATCH] (vesa)menu.c32: Add support for BLS
On Sat, May 25, 2019 at 3:42 PM Sebastian Herbszt <herbszt at gmx.de> wrote:> > Gregory Lee Bartholomew wrote: > > Modern distributions are moving toward a common boot scheme called > > "The Boot Loader Specification". > > Which distributions are using this yet? > > > This patch enables syslinux's > > (vesa)menu.c32 modules to parse the drop-in files that are defined by > > this new specification. > > Any reason why you don't try to implement this in syslinux core? > > <snip> > > > +static int parse_bls1_file(struct blsdata *bd, const char *filename) > > +{ > > + FILE *f = NULL; > > + char line[MAX_LINE], *p; > > + char *sort_field; > > + > > + dprintf("Opening bls entry: %s ", filename); > > + > > + f = fopen(filename, "r"); > > + dprintf("%s\n", f ? "ok" : "failed"); > > + > > + if (!f) > > + return -1; > > + > > + refstr_put(bd->filename); > > + bd->filename = refstrdup(filename); > > + > > + while (fgets(line, sizeof line, f)) { > > + p = strchr(line, '\r'); > > + if (p) > > + *p = '\0'; > > + p = strchr(line, '\n'); > > + if (p) > > + *p = '\0'; > > + > > + p = skipspace(line); > > + > > + if (looking_at(p, "title")) { > > + refstr_put(bd->title); > > + bd->title = refstrdup(skipspace(p + 5)); > > + } else if (looking_at(p, "version")) { > > + refstr_put(bd->version); > > + bd->version = refstrdup(skipspace(p + 7)); > > + bd->version0 = padver(bd->version); > > + } else if (looking_at(p, "machine-id")) { > > + refstr_put(bd->machine_id); > > + bd->machine_id = refstrdup(skipspace(p + 10)); > > + } else if (looking_at(p, "linux")) { > > + refstr_put(bd->linux_); > > + bd->linux_ = refstrdup(skipspace(p + 5)); > > + } else if (looking_at(p, "initrd")) { > > + refstr_put(bd->initrd); > > + bd->initrd = refstrdup(skipspace(p + 6)); > > According to the specification "initrd" may appear more than once.Sorry, I missed a few of your questions in my earlier response. Ah, I missed that. I guess I'll have to take a look at how syslinux handles multiple initrd's and do something similar.> > > + } else if (looking_at(p, "efi")) { > > + refstr_put(bd->efi); > > + bd->efi = refstrdup(skipspace(p + 3)); > > + } else if (looking_at(p, "options")) { > > + /* The "options" keyword can be specified multiple times > > */ > > + int len = bd->options ? strlen(bd->options) : 0; > > + int xlen; > > + p = skipspace(p + 7); > > + xlen = strlen(p); > > + if (len && xlen) { > > + /* Grab one space char from the file */ > > + p--; > > + xlen++; > > + } > > + bd->options = realloc(bd->options, len + xlen + 1); > > + memcpy(bd->options + len, p, xlen + 1); > > + } else if (looking_at(p, "devicetree")) { > > + refstr_put(bd->devicetree); > > + bd->devicetree = refstrdup(skipspace(p + 10)); > > + } else if (looking_at(p, "architecture")) { > > + refstr_put(bd->architecture); > > + bd->architecture = refstrdup(skipspace(p + 12)); > > + } > > + } > > + > > + fclose(f); > > + > > + p = get_word(bls_sort_by, &sort_field); > > + while (sort_field && *sort_field != '\0') { > > + const char *sf = NULL; > > + > > + if (looking_at(sort_field, "title")) { > > + sf = bd->title; > > + } else if (looking_at(sort_field, "version")) { > > + sf = bd->version0; > > + } else if (looking_at(sort_field, "machine-id")) { > > + sf = bd->machine_id; > > + } > > + > > + if (sf) { > > + bd->sort_field = realloc( > > + bd->sort_field, > > + strlen(bd->sort_field) + strlen(sf) + 1 > > + ); > > + strcat(bd->sort_field, sf); > > + } > > + p = get_word(skipspace(p), &sort_field); > > + } > > + > > + return (bd->linux_ || bd->efi) ? 0 : -1; > > +} > > <snip> > > > +static int parse_bls1_dir(const char *dirname) > > +{ > > + DIR *d = NULL; > > + char *filename = NULL; > > + struct dirent *de = NULL; > > + struct blsdata *nbd = NULL, **bdx = NULL; > > + int i, n_bdx = 0, n_bd = 0; > > + int rv = -1, fn_len, dn_len; > > + struct menu *m = current_menu; > > + > > + if (!*dirname) > > + return -1; > > + > > + dprintf("Opening bls entries directory %s ", dirname); > > + > > + d = opendir(dirname); > > + dprintf("%s\n", d ? "ok" : "failed"); > > + > > + if (!d) > > + return -1; > > + > > + dn_len = strlen(dirname); > > + > > + /* Process up to 128 files */ > > + /* https://wiki.syslinux.org/wiki/ > > + index.php?title=Syslinux_1_Changelog#Changes_in_1.37 */ > > + while ((de = readdir(d)) != NULL && n_bd < 128) { > > Are you sure this limit is still accurate?No, I'm not. It seemed like a reasonable limit though. If the vote is that there should not be a limit, I'm cool with taking it out. The only other place in the code that I wrote that might be impacted is the auto-numbering for the labels. I reserved only three digits for the auto-numbered label names -- BLS000 ... BLS127. I'm not sure if that is the best way to handle the labels anyway. If anyone has suggestions, I'm all ears. Thanks.