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.