From ee2c6d4160c99d2500c36dbea4a8e592d1af3f52 Mon Sep 17 00:00:00 2001 From: Philipp Kern Date: Thu, 24 Aug 2017 22:11:21 +0200 Subject: [PATCH] zipl: Allow optional entries that are left out when files are missing. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Debian carried a patch forever that allowed zipl to run even if not all menu items had files attached. If a required file is missing for an entry (e.g. vmlinuz.old or initrd.img.old) and it is marked as "optional" in the config, the section will be skipped. This allows zipl to install after bootstrapping, as booting on s390 still relies on the kernel/initrd symlinks in the root directory. Closes: https://github.com/ibm-s390-linux/s390-tools/pull/2 Signed-off-by: Philipp Kern Reviewed-by: Peter Oberparleiter [sth@linux.ibm.com: adapted patches to latest changes, merged patches] Signed-off-by: Stefan Haberland Signed-off-by: Jan Höppner --- zipl/include/job.h | 4 ++++ zipl/include/scan.h | 3 ++- zipl/man/zipl.conf.5.in | 17 ++++++++++++++ zipl/src/boot.c | 4 ++++ zipl/src/bootmap.c | 6 +++++ zipl/src/job.c | 52 ++++++++++++++++++++++++++++++++--------- zipl/src/scan.c | 25 ++++++++++---------- 7 files changed, 87 insertions(+), 24 deletions(-) diff --git a/zipl/include/job.h b/zipl/include/job.h index 4be63472..0090c652 100644 --- a/zipl/include/job.h +++ b/zipl/include/job.h @@ -13,6 +13,8 @@ #ifndef JOB_H #define JOB_H +#include + #include "disk.h" #include "zipl.h" @@ -46,6 +48,8 @@ struct job_common_ipl_data { address_t image_addr; address_t parm_addr; address_t ramdisk_addr; + bool optional; + bool ignore; }; struct job_ipl_data { diff --git a/zipl/include/scan.h b/zipl/include/scan.h index e5e49abc..95f67942 100644 --- a/zipl/include/scan.h +++ b/zipl/include/scan.h @@ -16,7 +16,7 @@ #define SCAN_SECTION_NUM 9 -#define SCAN_KEYWORD_NUM 22 +#define SCAN_KEYWORD_NUM 23 #define SCAN_KEYWORD_ONLY_NUM 1 #define SCAN_AUTOMENU_NAME "zipl-automatic-menu" @@ -52,6 +52,7 @@ enum scan_keyword_id { scan_keyword_defaultauto = 19, scan_keyword_kdump = 20, scan_keyword_secure = 21, + scan_keyword_optional = 22, }; enum scan_section_type { diff --git a/zipl/man/zipl.conf.5.in b/zipl/man/zipl.conf.5.in index 217bf335..e9e66694 100644 --- a/zipl/man/zipl.conf.5.in +++ b/zipl/man/zipl.conf.5.in @@ -447,6 +447,23 @@ This option cannot be used together with either .BR 'segment' . .PP +.B optional += +.IR 0 / 1 +(configuration only) +.IP +.B Configuration section: +.br +If this option is set to 1 the configuration section will only be included in +the boot menu if the referenced image file exists, and running +.B zipl +will not fail if the image file is missing. + +The default value for +.B 'optional' +is 0. +.PP + .B parameters = .I kernel\-parameters diff --git a/zipl/src/boot.c b/zipl/src/boot.c index 6947f8e6..a5d1302b 100644 --- a/zipl/src/boot.c +++ b/zipl/src/boot.c @@ -394,6 +394,10 @@ store_stage2_menu(void* data, size_t size, struct job_data* job) return 0; /* Config texts */ for (i = 0; i < job->data.menu.num; i++) { + if (job->data.menu.entry[i].data.ipl.common.ignore) { + params->config[job->data.menu.entry[i].pos] = 0; + continue; + } const char *kdump_str = ""; if (job->data.menu.entry[i].data.ipl.is_kdump) kdump_str = " (kdump)"; diff --git a/zipl/src/bootmap.c b/zipl/src/bootmap.c index 304afafd..0ddc9899 100644 --- a/zipl/src/bootmap.c +++ b/zipl/src/bootmap.c @@ -1089,6 +1089,12 @@ build_program_table(int fd, char *filename, struct job_data *job, for (i=0; i < job->data.menu.num; i++) { switch (job->data.menu.entry[i].id) { case job_ipl: + if (job->data.menu.entry[i].data.ipl.common.ignore) { + printf("Skipping #%d: IPL section '%s' (missing files)\n", + job->data.menu.entry[i].pos, + job->data.menu.entry[i].name); + break; + } printf("Adding #%d: IPL section '%s'%s", job->data.menu.entry[i].pos, job->data.menu.entry[i].name, diff --git a/zipl/src/job.c b/zipl/src/job.c index ee900efb..81ac0735 100644 --- a/zipl/src/job.c +++ b/zipl/src/job.c @@ -758,7 +758,8 @@ static void error_text_section(const char *text, const char *section, const char static int -check_common_ipl_data(struct job_common_ipl_data *common, const char *section) +check_common_ipl_data(struct job_common_ipl_data *common, const char *section, + bool may_ignore) { uint64_t max_parm_size, len; char *buffer = NULL; @@ -768,10 +769,16 @@ check_common_ipl_data(struct job_common_ipl_data *common, const char *section) if (common->image != NULL) { rc = misc_read_file(common->image, &buffer, &size, 0); if (rc) { - error_text_section("Image file", section, common->image); + if (may_ignore && common->optional) { + printf("Optional section '%s': Missing image file '%s'\n", + section, common->image); + error_clear_reason(); + common->ignore = true; + rc = 0; + goto skip_image; + } return rc; } - if (size < MAX_COMMAND_LINE_SIZE + sizeof(uint64_t)) { error_text_section("Image file", section, common->image); return -1; @@ -789,12 +796,19 @@ check_common_ipl_data(struct job_common_ipl_data *common, const char *section) return -1; } } - +skip_image: if (common->ramdisk != NULL) { rc = misc_check_readable_file(common->ramdisk); if (rc) { - error_text_section("Ramdisk file", section, common->ramdisk); - return rc; + if (common->optional) { + printf("Optional section '%s': Missing ramdisk file '%s'\n", + section, common->ramdisk); + error_clear_reason(); + common->ignore = true; + rc = 0; + } else { + return rc; + } } } return 0; @@ -802,13 +816,17 @@ check_common_ipl_data(struct job_common_ipl_data *common, const char *section) static int check_job_ipl_data(struct job_ipl_data *ipl, char *name, - struct job_envblk_data *envblk) + struct job_envblk_data *envblk, bool may_ignore) { int rc; - rc = check_common_ipl_data(&ipl->common, name); + rc = check_common_ipl_data(&ipl->common, name, may_ignore); if (rc) return rc; + + if (ipl->common.ignore) + return 0; + return finalize_ipl_address_data(ipl, name, envblk); } @@ -887,9 +905,15 @@ check_job_menu_data(struct job_menu_data *menu, struct job_envblk_data *envblk) case job_ipl: rc = check_job_ipl_data(&menu->entry[i].data.ipl, menu->entry[i].name, - envblk); + envblk, true); if (rc) return rc; + /* default_pos is 1-indexed */ + if (menu->default_pos == i + 1 && + menu->entry[i].data.ipl.common.ignore) { + error_text("Cannot ignore default entry"); + return -1; + } break; case job_print_usage: case job_print_version: @@ -917,7 +941,7 @@ check_job_ipl_tape_data(struct job_ipl_tape_data *ipl, char* name) return rc; } } - rc = check_common_ipl_data(&ipl->common, name); + rc = check_common_ipl_data(&ipl->common, name, false); if (rc) return rc; return finalize_common_address_data(&ipl->common, name); @@ -1016,7 +1040,7 @@ check_job_data(struct job_data* job) break; case job_ipl: rc = check_job_ipl_data(&job->data.ipl, job->name, - &job->envblk); + &job->envblk, false); break; case job_menu: rc = check_job_menu_data(&job->data.menu, &job->envblk); @@ -1295,6 +1319,12 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section) if (rc) return rc; } + job->data.ipl.common.optional = false; + if (data[(int) scan_keyword_optional] != NULL) { + job->data.ipl.common.optional = + atoi(data[(int) scan_keyword_optional]) == 1; + } + job->data.ipl.common.ignore = false; break; case section_ipl_tape: /* Tape IPL job */ diff --git a/zipl/src/scan.c b/zipl/src/scan.c index b6b94262..0248f1d2 100644 --- a/zipl/src/scan.c +++ b/zipl/src/scan.c @@ -47,45 +47,45 @@ enum scan_key_state scan_key_table[SCAN_SECTION_NUM][SCAN_KEYWORD_NUM] = { * ult to tofs e mete file isk ent et pt out ultm dump * rs enu * - * targ targ targ targ targ defa kdum secu - * etba etty etge etbl etof ulta p re + * targ targ targ targ targ defa kdum secu opti + * etba etty etge etbl etof ulta p re onal * se pe omet ocks fset uto * ry ize */ /* default auto */ {opt, inv, inv, inv, inv, inv, inv, inv, req, opt, opt, inv, inv, inv, - opt, opt, opt, opt, opt, opt, inv, opt}, + opt, opt, opt, opt, opt, opt, inv, opt, inv}, /* default menu */ {inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, - inv, inv, inv, inv, inv, inv, inv, opt}, + inv, inv, inv, inv, inv, inv, inv, opt, inv}, /* default section */ {req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, - inv, inv, inv, inv, inv, inv, inv, opt}, + inv, inv, inv, inv, inv, inv, inv, opt, inv}, /* ipl */ {inv, inv, inv, req, opt, opt, opt, inv, req, inv, inv, inv, inv, inv, - opt, opt, opt, opt, opt, inv, opt, opt}, + opt, opt, opt, opt, opt, inv, opt, opt, opt}, /* segment load */ {inv, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv, - inv, inv, inv, inv, inv, inv, inv, inv}, + inv, inv, inv, inv, inv, inv, inv, inv, inv}, /* part dump */ {inv, req, inv, inv, inv, inv, inv, inv, opt, inv, inv, inv, inv, inv, - inv, inv, inv, inv, inv, inv, inv, inv}, + inv, inv, inv, inv, inv, inv, inv, inv, inv}, /* fs dump */ {inv, inv, req, inv, opt, opt, inv, inv, req, inv, inv, inv, inv, inv, - inv, inv, inv, inv, inv, inv, inv, inv}, + inv, inv, inv, inv, inv, inv, inv, inv, inv}, /* ipl tape */ {inv, inv, inv, req, opt, opt, opt, inv, inv, inv, inv, inv, req, inv, - inv, inv, inv, inv, inv, inv, inv, inv}, + inv, inv, inv, inv, inv, inv, inv, inv, inv}, /* multi volume dump */ {inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, - inv, inv, inv, inv, inv, inv, inv, inv} + inv, inv, inv, inv, inv, inv, inv, inv, inv} }; /* Determines which keyword may be present in a menu section */ static enum scan_key_state scan_menu_key_table[SCAN_KEYWORD_NUM] = { /* menu section */ opt, inv, inv, inv, inv, inv, inv, inv, req, opt, opt, inv, inv, inv, - opt, opt, opt, opt, opt, inv, inv, opt + opt, opt, opt, opt, opt, inv, inv, opt, inv }; /* Mapping of keyword IDs to strings */ @@ -114,6 +114,7 @@ static const struct { { "tape", scan_keyword_tape}, { "kdump", scan_keyword_kdump}, { "secure", scan_keyword_secure}, + { "optional", scan_keyword_optional}, }; /* List of keywords that are used without an assignment */