11 #include <file/file.h>
12 #include <talloc/talloc.h>
13 #include <i18n/i18n.h>
16 #include "discover/parser-conf.h"
17 #include "discover/parser.h"
19 static const char *const bls_dirs[] = {
21 "/boot/loader/entries",
26 struct discover_boot_option *opt;
27 struct grub2_script *script;
32 const char *machine_id;
38 static char *field_append(struct bls_state *state, int type, char *buffer,
39 char *start, char *end)
41 char *temp = talloc_strndup(state, start, end - start + 1);
42 const char *field = temp;
44 if (type == GRUB2_WORD_VAR) {
45 field = script_env_get(state->script, temp);
51 buffer = talloc_strdup(state->opt, field);
53 buffer = talloc_asprintf_append(buffer, "%s", field);
58 static char *expand_field(struct bls_state *state, char *value)
63 int type = GRUB2_WORD_TEXT;
68 buffer = field_append(state, type, buffer,
74 type = GRUB2_WORD_VAR;
76 } else if (type == GRUB2_WORD_VAR) {
77 if (!isalnum(*value) && *value != '_') {
78 buffer = field_append(state, type, buffer,
80 type = GRUB2_WORD_TEXT;
90 buffer = field_append(state, type, buffer,
99 static void bls_process_pair(struct conf_context *conf, const char *name,
102 struct bls_state *state = conf->parser_info;
103 struct discover_boot_option *opt = state->opt;
104 struct boot_option *option = opt->option;
106 if (streq(name, "title")) {
107 state->title = expand_field(state, value);
111 if (streq(name, "version")) {
112 state->version = expand_field(state, value);
116 if (streq(name, "machine-id")) {
117 state->machine_id = expand_field(state, value);
121 if (streq(name, "linux")) {
122 state->image = expand_field(state, value);
126 if (streq(name, "initrd")) {
127 state->initrd = expand_field(state, value);
131 if (streq(name, "devicetree")) {
132 state->dtb = expand_field(state, value);
136 if (streq(name, "options")) {
137 option->boot_args = expand_field(state, value);
142 static bool option_is_default(struct bls_state *state,
143 struct boot_option *option)
149 var = script_env_get(state->script, "default");
153 if (!strcmp(var, option->id))
156 if (!strcmp(var, option->name))
159 idx = strtoul(var, &end, 10);
160 return end != var && *end == '\0' && idx == state->idx;
163 static void bls_finish(struct conf_context *conf)
165 struct bls_state *state = conf->parser_info;
166 struct discover_context *dc = conf->dc;
167 struct discover_boot_option *opt = state->opt;
168 struct boot_option *option = opt->option;
173 device_handler_status_dev_info(dc->handler, dc->device,
174 _("linux field not found in %s"),
179 filename = basename(state->filename);
180 filename[strlen(filename) - strlen(".conf")] = '\0';
182 option->id = talloc_strdup(option, filename);
185 option->name = talloc_strdup(option, state->title);
186 else if (state->machine_id && state->version)
187 option->name = talloc_asprintf(option, "%s %s",
190 else if (state->version)
191 option->name = talloc_strdup(option, state->version);
193 option->name = talloc_strdup(option, state->image);
195 root = script_env_get(state->script, "root");
197 opt->boot_image = create_grub2_resource(opt, conf->dc->device,
201 opt->initrd = create_grub2_resource(opt, conf->dc->device,
202 root, state->initrd);
205 opt->dtb = create_grub2_resource(opt, conf->dc->device,
208 char* args_sigfile_default = talloc_asprintf(opt,
209 "%s.cmdline.sig", state->image);
210 opt->args_sig_file = create_grub2_resource(opt, conf->dc->device,
211 root, args_sigfile_default);
212 talloc_free(args_sigfile_default);
214 option->is_default = option_is_default(state, option);
216 list_add_tail(&state->script->options, &opt->list);
217 state->script->n_options++;
219 device_handler_status_dev_info(dc->handler, dc->device,
220 _("Created menu entry from BLS file %s"),
224 static int bls_filter(const struct dirent *ent)
226 int offset = strlen(ent->d_name) - strlen(".conf");
231 return strncmp(ent->d_name + offset, ".conf", strlen(".conf")) == 0;
234 static int bls_sort(const struct dirent **ent_a, const struct dirent **ent_b)
236 return strverscmp((*ent_a)->d_name, (*ent_b)->d_name);
239 int builtin_blscfg(struct grub2_script *script,
240 void *data __attribute__((unused)),
241 int argc __attribute__((unused)),
242 char *argv[] __attribute__((unused)));
244 int builtin_blscfg(struct grub2_script *script,
245 void *data __attribute__((unused)),
246 int argc __attribute__((unused)),
247 char *argv[] __attribute__((unused)))
249 unsigned int current_idx = script->n_options;
250 struct discover_context *dc = script->ctx;
251 struct dirent **bls_entries;
252 struct conf_context *conf;
253 struct bls_state *state;
254 char *buf, *filename;
255 const char * const *dir;
260 conf = talloc_zero(dc, struct conf_context);
265 conf->get_pair = conf_get_pair_space;
266 conf->process_pair = bls_process_pair;
267 conf->finish = bls_finish;
269 blsdir = script_env_get(script, "blsdir");
271 for (dir = bls_dirs; *dir; dir++)
272 if (!parser_stat_path(dc, dc->device, *dir, &statbuf)) {
278 device_handler_status_dev_info(dc->handler, dc->device,
279 _("BLS directory wasn't found"));
283 n = parser_scandir(dc, blsdir, &bls_entries, bls_filter, bls_sort);
288 filename = talloc_asprintf(dc, "%s/%s", blsdir,
289 bls_entries[n]->d_name);
293 state = talloc_zero(conf, struct bls_state);
297 state->opt = discover_boot_option_create(dc, dc->device);
301 state->script = script;
302 state->filename = filename;
303 state->idx = current_idx++;
304 conf->parser_info = state;
306 rc = parser_request_file(dc, dc->device, filename, &buf, &len);
310 conf_parse_buf(conf, buf, len);
314 talloc_free(filename);
315 free(bls_entries[n]);
319 device_handler_status_dev_info(dc->handler, dc->device,
320 _("Scanning %s failed"),
323 free(bls_entries[n]);