mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zipl: Add BootLoaderSpec support
The BootLoaderSpec (BLS) defines a file format for boot configurations, so bootloaders can parse these files and create their boot menu entries by using the information provided by them [0]. This allow to configure the boot items as drop-in files in a directory instead of having to parse and modify a bootloader configuration file. If the /boot/loader/entries exists and there are BLS files there, then these are parsed and configuration sections are added without the need to have these in a zipl.conf file. A different BLS directory can be specified from the command line using the --blsdir option. [0]: https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/ GitHub-ID: #28 Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> Reviewed-by: Stefan Haberland <sth@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
e04acab0ed
commit
d280e5b1fa
@@ -119,6 +119,7 @@ extern enum scan_key_state scan_key_table[SCAN_SECTION_NUM][SCAN_KEYWORD_NUM];
|
||||
|
||||
|
||||
int scan_file(const char* filename, struct scan_token** array);
|
||||
int scan_bls(const char* blsdir, struct scan_token** token, int scan_size);
|
||||
void scan_free(struct scan_token* array);
|
||||
char* scan_keyword_name(enum scan_keyword_id id);
|
||||
int scan_check_defaultboot(struct scan_token* scan);
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
#define ZIPL_CONF_VAR "ZIPLCONF"
|
||||
#define ZIPL_DEFAULT_CONF "/etc/zipl.conf"
|
||||
#define ZIPL_DEFAULT_BLSDIR "/boot/loader/entries"
|
||||
|
||||
#define MENU_DEFAULT_PROMPT 0
|
||||
#define MENU_DEFAULT_TIMEOUT 0
|
||||
|
||||
@@ -25,7 +25,7 @@ loading a data file to initialize named saved segments (NSS)
|
||||
Each of these operations is characterized by a boot configuration, i.e. a
|
||||
set of required parameters.
|
||||
.B zipl
|
||||
supports two ways of specifying a boot configuration:
|
||||
supports three ways of specifying a boot configuration:
|
||||
.IP " -"
|
||||
.B command line:
|
||||
all parameters are provided through the command line switches described below.
|
||||
@@ -37,6 +37,11 @@ parameters are provided by sections defined in a configuration file (see
|
||||
Using a configuration file, you can either specify a single boot configuration
|
||||
or a menu, i.e. a list of configurations from which users can choose at boot
|
||||
time.
|
||||
.IP " -"
|
||||
.B BLS config files:
|
||||
boot configurations are specified using BootLoaderSpec (BLS) configuration files. The
|
||||
.BR zipl.conf (5)
|
||||
configuration file is still used to specify parameters or aditional boot configurations.
|
||||
.PP
|
||||
|
||||
To use a single boot configuration section, provide its name as parameter to
|
||||
@@ -117,6 +122,11 @@ Print version information, then exit.
|
||||
Use the specified <CONFIG FILE>. If none is supplied, the environment
|
||||
variable ZIPLCONF is evaluated if set, otherwise /etc/zipl.conf is used.
|
||||
|
||||
.TP
|
||||
.BR "\-b <BLS DIRECTORY>" " or " "\-\-blsdir=<BLS DIRECTORY>"
|
||||
Use the specified <BLS DIRECTORY> to parse BootLoaderSpec config files.
|
||||
If none is supplied, the /boot/loader/entries directory is used.
|
||||
|
||||
.TP
|
||||
.BR "\-t <TARGET DIRECTORY>" " or " "\-\-target=<TARGET DIRECTORY>"
|
||||
Use the specified <TARGET DIRECTORY>.
|
||||
|
||||
@@ -117,6 +117,27 @@ timeout = 0
|
||||
.br
|
||||
.PP
|
||||
|
||||
.B BootLoaderSpec configuration files
|
||||
|
||||
Another way to specify IPL sections is to use BLS config files. These are
|
||||
configuration files located by default at /boot/loader/entries, but another
|
||||
location can be specified using the '\-\-blsdir' option of zipl.
|
||||
|
||||
.IP
|
||||
# An example for a BLS configuration file
|
||||
.br
|
||||
|
||||
version 4.15.9
|
||||
.br
|
||||
linux /vmlinuz-4.15.9
|
||||
.br
|
||||
initrd /initramfs-4.15.9
|
||||
.br
|
||||
options root=/dev/dasda1 console=ttyS0
|
||||
.PP
|
||||
|
||||
The location of the linux and initrd has to be specified relative to the boot partition. The BLS config files are only used to specify the IPL sections, a zipl.conf configuration files is still needed for global parameters.
|
||||
|
||||
.B Boot menu
|
||||
|
||||
The
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
/* Command line options */
|
||||
static struct option options[] = {
|
||||
{ "config", required_argument, NULL, 'c'},
|
||||
{ "blsdir", required_argument, NULL, 'b'},
|
||||
{ "target", required_argument, NULL, 't'},
|
||||
{ "targetbase", required_argument, NULL, 0xaa},
|
||||
{ "targettype", required_argument, NULL, 0xab},
|
||||
@@ -55,11 +56,12 @@ static struct option options[] = {
|
||||
};
|
||||
|
||||
/* Command line option abbreviations */
|
||||
static const char option_string[] = "-c:t:i:r:p:P:d:D:M:s:m:hHnVvaT:fk:";
|
||||
static const char option_string[] = "-c:b:t:i:r:p:P:d:D:M:s:m:hHnVvaT:fk:";
|
||||
|
||||
struct command_line {
|
||||
char* data[SCAN_KEYWORD_NUM];
|
||||
char* config;
|
||||
char *blsdir;
|
||||
char* menu;
|
||||
char* section;
|
||||
int help;
|
||||
@@ -197,6 +199,14 @@ get_command_line(int argc, char* argv[], struct command_line* line)
|
||||
} else
|
||||
cmdline.config = optarg;
|
||||
break;
|
||||
case 'b':
|
||||
if (cmdline.blsdir != NULL) {
|
||||
error_reason("Option 'blsdir' specified more "
|
||||
"than once");
|
||||
rc = -1;
|
||||
} else
|
||||
cmdline.blsdir = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
if (cmdline.menu != NULL) {
|
||||
error_reason("Option 'menu' specified more "
|
||||
@@ -1731,6 +1741,7 @@ get_job_from_config_file(struct command_line* cmdline, struct job_data* job)
|
||||
struct scan_token* scan;
|
||||
struct scan_token* new_scan;
|
||||
char* filename;
|
||||
char *blsdir;
|
||||
char* source;
|
||||
int rc, scan_size;
|
||||
|
||||
@@ -1755,6 +1766,17 @@ get_job_from_config_file(struct command_line* cmdline, struct job_data* job)
|
||||
error_text("Config file '%s'", filename);
|
||||
return scan_size;
|
||||
}
|
||||
/* Check if a BLS directory was provided on command line */
|
||||
if (cmdline->blsdir != NULL) {
|
||||
blsdir = cmdline->blsdir;
|
||||
} else {
|
||||
blsdir = ZIPL_DEFAULT_BLSDIR;
|
||||
}
|
||||
rc = scan_bls(blsdir, &scan, scan_size);
|
||||
if (rc) {
|
||||
error_text("BLS parsing '%s'", blsdir);
|
||||
return rc;
|
||||
}
|
||||
if ((cmdline->menu == NULL) && (cmdline->section == NULL)) {
|
||||
rc = scan_check_defaultboot(scan);
|
||||
if (rc < 0) {
|
||||
|
||||
179
zipl/src/scan.c
179
zipl/src/scan.c
@@ -16,13 +16,21 @@
|
||||
#define __USE_ISOC99
|
||||
#endif
|
||||
|
||||
/* Need GNU function strverscmp() in dirent.h */
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "lib/util_base.h"
|
||||
|
||||
#include "boot.h"
|
||||
@@ -633,6 +641,177 @@ scan_file(const char* filename, struct scan_token** token)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
bls_filter(const struct dirent *ent)
|
||||
{
|
||||
int offset = strlen(ent->d_name) - strlen(".conf");
|
||||
|
||||
if (offset < 0)
|
||||
return 0;
|
||||
|
||||
return strncmp(ent->d_name + offset, ".conf", strlen(".conf")) == 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
bls_sort(const struct dirent **ent_a, const struct dirent **ent_b)
|
||||
{
|
||||
return strverscmp((*ent_a)->d_name, (*ent_b)->d_name);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
scan_append_section_heading(struct scan_token* scan, int* index, char* name);
|
||||
static int
|
||||
scan_append_keyword_assignment(struct scan_token* scan, int* index,
|
||||
enum scan_keyword_id id, char* value);
|
||||
|
||||
|
||||
static int
|
||||
scan_bls_field(struct misc_file_buffer *file, struct scan_token* scan,
|
||||
int* index)
|
||||
{
|
||||
int current;
|
||||
int key_start, key_end;
|
||||
int val_start, val_end;
|
||||
char *val;
|
||||
|
||||
for (key_start = file->pos; ; file->pos++) {
|
||||
current = misc_get_char(file, 0);
|
||||
|
||||
if (isblank(current)) {
|
||||
key_end = file->pos;
|
||||
skip_blanks(file);
|
||||
val_start = file->pos;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isalnum(current) && current != '_' && current != '-')
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (; ; file->pos++) {
|
||||
current = misc_get_char(file, 0);
|
||||
|
||||
if (current == '\n' || current == EOF)
|
||||
break;
|
||||
}
|
||||
|
||||
val_end = file->pos;
|
||||
file->buffer[key_end] = '\0';
|
||||
file->buffer[val_end] = '\0';
|
||||
|
||||
if (strncmp("version", &file->buffer[key_start], key_end - key_start) == 0) {
|
||||
scan_append_section_heading(scan, index, &file->buffer[val_start]);
|
||||
}
|
||||
|
||||
if (strncmp("linux", &file->buffer[key_start], key_end - key_start) == 0) {
|
||||
misc_asprintf(&val, "%s", &file->buffer[val_start]);
|
||||
scan_append_keyword_assignment(scan, index, scan_keyword_image, val);
|
||||
free(val);
|
||||
}
|
||||
|
||||
if (strncmp("options", &file->buffer[key_start], key_end - key_start) == 0) {
|
||||
scan_append_keyword_assignment(scan, index, scan_keyword_parameters,
|
||||
&file->buffer[val_start]);
|
||||
}
|
||||
|
||||
if (strncmp("initrd", &file->buffer[key_start], key_end - key_start) == 0) {
|
||||
misc_asprintf(&val, "%s", &file->buffer[val_start]);
|
||||
scan_append_keyword_assignment(scan, index, scan_keyword_ramdisk, val);
|
||||
free(val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
scan_bls(const char* blsdir, struct scan_token** token, int scan_size)
|
||||
{
|
||||
int count = 0;
|
||||
int size, remaining = 0, n, current, rc = -1;
|
||||
struct scan_token* buffer;
|
||||
struct scan_token* array = *token;
|
||||
struct dirent** bls_entries;
|
||||
struct misc_file_buffer file;
|
||||
struct stat sb;
|
||||
char filename[PATH_MAX];
|
||||
|
||||
if (!(stat(blsdir, &sb) == 0 && S_ISDIR(sb.st_mode)))
|
||||
return 0;
|
||||
|
||||
n = scandir(blsdir, &bls_entries, bls_filter, bls_sort);
|
||||
if (n <= 0)
|
||||
return n;
|
||||
|
||||
while (array[count].id != 0)
|
||||
count++;
|
||||
|
||||
remaining = scan_size - count;
|
||||
|
||||
if (remaining < n) {
|
||||
size = scan_size - remaining + n;
|
||||
buffer = (struct scan_token *)misc_malloc(size * sizeof(struct scan_token));
|
||||
if (!buffer)
|
||||
goto err;
|
||||
memset(buffer, 0, size * sizeof(struct scan_token));
|
||||
memcpy(buffer, array, count * sizeof(struct scan_token));
|
||||
} else {
|
||||
buffer = array;
|
||||
}
|
||||
|
||||
while (n--) {
|
||||
sprintf(filename, "%s/%s", blsdir, bls_entries[n]->d_name);
|
||||
printf("Using BLS config file '%s'\n", filename);
|
||||
|
||||
rc = misc_get_file_buffer(filename, &file);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
while ((size_t)file.pos < file.length) {
|
||||
current = misc_get_char(&file, 0);
|
||||
switch (current) {
|
||||
case '#':
|
||||
file.pos++;
|
||||
skip_line(&file);
|
||||
break;
|
||||
case EOF:
|
||||
break;
|
||||
case '\t':
|
||||
case '\0':
|
||||
case ' ':
|
||||
file.pos++;
|
||||
break;
|
||||
default:
|
||||
rc = scan_bls_field(&file, buffer, &count);
|
||||
if (rc) {
|
||||
error_reason("Incorrect BLS field in "
|
||||
"config file %s\n", filename);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
misc_free_file_buffer(&file);
|
||||
free(bls_entries[n]);
|
||||
}
|
||||
|
||||
*token = buffer;
|
||||
rc = 0;
|
||||
err:
|
||||
if (n > 0) {
|
||||
do {
|
||||
free(bls_entries[n]);
|
||||
} while (n-- > 0);
|
||||
}
|
||||
|
||||
free(bls_entries);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Search scanned tokens SCAN for a section/menu heading (according to
|
||||
* TYPE) of the given NAME, beginning at token OFFSET. Return the index of
|
||||
* the section/menu heading on success, a negative value on error. */
|
||||
|
||||
@@ -54,6 +54,7 @@ static const char* usage_text[] = {
|
||||
"-h, --help Print this help, then exit",
|
||||
"-v, --version Print version information, then exit",
|
||||
"-c, --config CONFIGFILE Read configuration from CONFIGFILE",
|
||||
"-b, --blsdir BLSDIR Parse BootLoaderSpec files from BLSDIR",
|
||||
"-t, --target TARGETDIR Write bootmap file to TARGETDIR and install",
|
||||
" bootloader on device containing TARGETDIR",
|
||||
" --targetbase BASEDEVICE Install bootloader on BASEDEVICE",
|
||||
|
||||
Reference in New Issue
Block a user