X-Git-Url: https://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=discover%2Fsyslinux-parser.c;h=be7b94aa5d5b2ccb625ebea1fc23212fda8784c2;hp=d948765bf52ab68558e827af4b933df9341ac52e;hb=281b1398778cdcde08aa8a6a96d0d8c7794fd259;hpb=aa23987dd043f7c8bea5a48bd9476a4ca1620069 diff --git a/discover/syslinux-parser.c b/discover/syslinux-parser.c index d948765..be7b94a 100644 --- a/discover/syslinux-parser.c +++ b/discover/syslinux-parser.c @@ -36,6 +36,11 @@ struct syslinux_options { char *cfg_dir; }; +struct conf_file_stat { + char *name; + struct stat stat; + struct list_item list; +}; static const char *const syslinux_conf_files[] = { "/boot/syslinux/syslinux.cfg", @@ -285,7 +290,7 @@ static void syslinux_process_pair(struct conf_context *conf, const char *name, c static void syslinux_finalize(struct conf_context *conf) { struct syslinux_options *state = conf->parser_info; - struct syslinux_boot_option *syslinux_opt; + struct syslinux_boot_option *syslinux_opt, *tmp; struct discover_context *dc = conf->dc; struct discover_boot_option *d_opt; bool implicit_image = true; @@ -404,16 +409,24 @@ static void syslinux_finalize(struct conf_context *conf) discover_context_add_boot_option(dc, d_opt); continue; + fail: talloc_free(d_opt); } + + list_for_each_entry_safe(&state->processed_options, syslinux_opt, tmp, list) + talloc_free(syslinux_opt); + list_init(&state->processed_options); } static int syslinux_parse(struct discover_context *dc) { + struct conf_file_stat *confcmp, *confdat; + struct list processed_conf_files; struct syslinux_options *state; const char * const *filename; struct conf_context *conf; + struct stat statbuf; char *cfg_dir; int len, rc; char *buf; @@ -436,6 +449,8 @@ static int syslinux_parse(struct discover_context *dc) conf->parser_info = state = talloc_zero(conf, struct syslinux_options); list_init(&state->processed_options); + list_init(&processed_conf_files); + /* * set the global defaults * by spec 'default' defaults to 'linux' and @@ -448,10 +463,37 @@ static int syslinux_parse(struct discover_context *dc) conf_set_global_option(conf, "append", ""); for (filename = syslinux_conf_files; *filename; filename++) { + /* + * guard against duplicate entries in case-insensitive + * filesystems, mainly vfat boot partitions + */ + rc = parser_stat_path(dc, dc->device, *filename, &statbuf); + if (rc) + continue; + + rc = 0; + + list_for_each_entry(&processed_conf_files, confcmp, list) { + if (confcmp->stat.st_ino == statbuf.st_ino) { + pb_log("conf file %s is a path duplicate of %s..skipping\n", + *filename, confcmp->name); + rc = 1; + break; + } + } + + if (rc) + continue; + rc = parser_request_file(dc, dc->device, *filename, &buf, &len); if (rc) continue; + confdat = talloc_zero(conf, struct conf_file_stat); + confdat->stat = statbuf; + confdat->name = talloc_strdup(confdat, *filename); + list_add(&processed_conf_files, &confdat->list); + /* * save location of root config file for possible * INCLUDE directives later