1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
From c4df63488b9e09a9aa69e32ea5c0671c9dc50c9d Mon Sep 17 00:00:00 2001
From: Gatis Paeglis <gatis.paeglis@qt.io>
Date: Wed, 24 Aug 2016 12:29:38 +0200
Subject: [PATCH] Create firmware convenience symlinks.
Later this could be moved into utils or a similar
location, if other boot loader backends will need
this functionality.
---
src/libostree/ostree-bootloader-uboot.c | 93 ++++++++++++++++++++++++++++++++-
1 file changed, 92 insertions(+), 1 deletion(-)
diff --git a/src/libostree/ostree-bootloader-uboot.c b/src/libostree/ostree-bootloader-uboot.c
index 22251da..26a3127 100644
--- a/src/libostree/ostree-bootloader-uboot.c
+++ b/src/libostree/ostree-bootloader-uboot.c
@@ -62,6 +62,97 @@ _ostree_bootloader_uboot_get_name (OstreeBootloader *bootloader)
return "U-Boot";
}
+/* It is common for firmware to search / on the boot partition for additional
+ * files that are required for booting. It can be difficult to change this search
+ * logic if it is hardcoded somewhere low in the stack or is in a read-only memory.
+ * This issue can be solved by system builders by creating a convenience symlink:
+ *
+ * cd sysroot/boot
+ * ln -s loader/second-stage-bootloader second-stage-bootloader
+ *
+ * This function will make sure that loader/second-stage-bootloader points to the
+ * correct target file version. This function does nothing if boot/ does not contain
+ * symlink files pointing into the loader/ directory.
+ */
+static gboolean
+create_firmware_convenience_symlinks (OstreeBootloaderUboot *self,
+ char *bootcsum_dir,
+ int bootversion,
+ GCancellable *cancellable,
+ GError **error)
+{
+ glnx_fd_close int loader_dfd = -1;
+ glnx_fd_close int boot_dfd = -1;
+ g_autofree char *loader_dir = NULL;
+ g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
+
+ loader_dir = g_strdup_printf ("boot/loader.%d/", bootversion);
+ if (!glnx_opendirat (self->sysroot->sysroot_fd, loader_dir, FALSE, &loader_dfd, error))
+ return FALSE;
+ if (!glnx_opendirat (self->sysroot->sysroot_fd, "boot", FALSE, &boot_dfd, error))
+ return FALSE;
+ if (!glnx_dirfd_iterator_init_take_fd (dup (boot_dfd), &dfd_iter, error))
+ return FALSE;
+
+ while (TRUE) {
+ struct dirent *dent;
+ struct stat stbuf;
+
+ if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error))
+ return FALSE;
+ if (dent == NULL)
+ break;
+
+ if (fstatat (dfd_iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) != 0)
+ {
+ if (errno == ENOENT)
+ continue;
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "fstatat");
+ return FALSE;
+ }
+
+ if (S_ISLNK(stbuf.st_mode))
+ {
+ char path_buffer[PATH_MAX];
+ g_autofree char *symlink_target = NULL;
+ symlink_target = glnx_readlinkat_malloc (boot_dfd, dent->d_name, cancellable, error);
+
+ if (g_str_has_prefix (symlink_target, "loader/"))
+ {
+ if (g_strcmp0 (dent->d_name, "uEnv.txt") == 0)
+ continue;
+
+ snprintf (path_buffer, sizeof(path_buffer), "%s/%s", bootcsum_dir, dent->d_name);
+ if (faccessat (boot_dfd, path_buffer + 1, F_OK, AT_SYMLINK_NOFOLLOW) == -1)
+ {
+ /* This bootcsum dir does not contain the final target, do nothing. */
+ if (errno == ENOENT)
+ continue;
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "faccessat");
+ return FALSE;
+ }
+
+ /* Cleanup from stray symlinks. This can happend when the previous deployment was
+ interrupted and no cleanup routines were run before restaring the deployment. */
+ if (unlinkat (loader_dfd, dent->d_name, 0) == -1 && errno != ENOENT)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "unlinkat");
+ return FALSE;
+ }
+ /* Complete the link chain to the current boot file version. */
+ snprintf (path_buffer, sizeof(path_buffer), "..%s/%s", bootcsum_dir, dent->d_name);
+ if (symlinkat (path_buffer, loader_dfd, dent->d_name) == -1)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "symlinkat");
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
static gboolean
create_config_from_boot_loader_entries (OstreeBootloaderUboot *self,
int bootversion,
@@ -138,7 +229,7 @@ create_config_from_boot_loader_entries (OstreeBootloaderUboot *self,
}
}
- return TRUE;
+ return create_firmware_convenience_symlinks (self, bootdir, bootversion, cancellable, error);
}
static gboolean
--
2.7.4
|