#include "find-esp.h"
#include "path-util.h"
#include "pe-header.h"
+#include "recurse-dir.h"
#include "sort-util.h"
#include "stat-util.h"
#include "strv.h"
}
static int boot_entry_load(
+ FILE *f,
const char *root,
- const char *path,
+ const char *dir,
+ const char *id,
BootEntry *entry) {
_cleanup_(boot_entry_free) BootEntry tmp = {
.type = BOOT_ENTRY_CONF,
};
- _cleanup_fclose_ FILE *f = NULL;
unsigned line = 1;
char *c;
int r;
+ assert(f);
assert(root);
- assert(path);
+ assert(dir);
+ assert(id);
assert(entry);
- r = path_extract_filename(path, &tmp.id);
- if (r < 0)
- return log_error_errno(r, "Failed to extract file name from path '%s': %m", path);
+ /* Loads a Type #1 boot menu entry from the specified FILE* object */
+
+ if (!efi_loader_entry_name_valid(id))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry name: %s", id);
- c = endswith_no_case(tmp.id, ".conf");
+ c = endswith_no_case(id, ".conf");
if (!c)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry file suffix: %s", tmp.id);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry file suffix: %s", id);
- if (!efi_loader_entry_name_valid(tmp.id))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry name: %s", tmp.id);
+ tmp.id = strdup(id);
+ if (!tmp.id)
+ return log_oom();
- tmp.id_old = strndup(tmp.id, c - tmp.id);
+ tmp.id_old = strndup(id, c - id); /* Without .conf suffix */
if (!tmp.id_old)
return log_oom();
- tmp.path = strdup(path);
+ tmp.path = path_join(dir, id);
if (!tmp.path)
return log_oom();
if (!tmp.root)
return log_oom();
- f = fopen(path, "re");
- if (!f)
- return log_error_errno(errno, "Failed to open \"%s\": %m", path);
-
for (;;) {
_cleanup_free_ char *buf = NULL, *field = NULL;
const char *p;
if (r == 0)
break;
if (r == -ENOBUFS)
- return log_error_errno(r, "%s:%u: Line too long", path, line);
+ return log_error_errno(r, "%s:%u: Line too long", tmp.path, line);
if (r < 0)
- return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
+ return log_error_errno(r, "%s:%u: Error while reading: %m", tmp.path, line);
line++;
p = buf;
r = extract_first_word(&p, &field, " \t", 0);
if (r < 0) {
- log_error_errno(r, "Failed to parse config file %s line %u: %m", path, line);
+ log_error_errno(r, "Failed to parse config file %s line %u: %m", tmp.path, line);
continue;
}
if (r == 0) {
- log_warning("%s:%u: Bad syntax", path, line);
+ log_warning("%s:%u: Bad syntax", tmp.path, line);
continue;
}
r = strv_extend_strv(&tmp.device_tree_overlay, l, false);
} else {
- log_notice("%s:%u: Unknown line \"%s\", ignoring.", path, line, field);
+ log_notice("%s:%u: Unknown line \"%s\", ignoring.", tmp.path, line, field);
continue;
}
if (r < 0)
- return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
+ return log_error_errno(r, "%s:%u: Error while reading: %m", tmp.path, line);
}
*entry = tmp;
BootEntry **entries,
size_t *n_entries) {
- _cleanup_strv_free_ char **files = NULL;
+ _cleanup_free_ DirectoryEntries *dentries = NULL;
+ _cleanup_close_ int dir_fd = -1;
int r;
assert(root);
assert(entries);
assert(n_entries);
- r = conf_files_list(&files, ".conf", NULL, 0, dir);
+ dir_fd = open(dir, O_DIRECTORY|O_CLOEXEC);
+ if (dir_fd < 0) {
+ if (errno == ENOENT)
+ return 0;
+
+ return log_error_errno(errno, "Failed to open '%s': %m", dir);
+ }
+
+ r = readdir_all(dir_fd, RECURSE_DIR_IGNORE_DOT, &dentries);
if (r < 0)
- return log_error_errno(r, "Failed to list files in \"%s\": %m", dir);
+ return log_error_errno(r, "Failed to read directory '%s': %m", dir);
+
+ for (size_t i = 0; i < dentries->n_entries; i++) {
+ const struct dirent *de = dentries->entries[i];
+ _cleanup_fclose_ FILE *f = NULL;
+
+ if (!dirent_is_file(de))
+ continue;
+
+ if (!endswith_no_case(de->d_name, ".conf"))
+ continue;
- STRV_FOREACH(f, files) {
if (!GREEDY_REALLOC0(*entries, *n_entries + 1))
return log_oom();
- r = boot_entry_load(root, *f, *entries + *n_entries);
+ r = xfopenat(dir_fd, de->d_name, "re", 0, &f);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to open %s/%s, ignoring: %m", dir, de->d_name);
+ continue;
+ }
+
+ r = fd_verify_regular(fileno(f));
+ if (r < 0) {
+ log_warning_errno(r, "File %s/%s is not regular, ignoring: %m", dir, de->d_name);
+ continue;
+ }
+
+ r = boot_entry_load(f, root, dir, de->d_name, *entries + *n_entries);
if (r < 0)
continue;