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 */