Coverage Report

Created: 2026-05-23 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ostree/src/libostree/ostree-bootloader-aboot.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2022 Eric Curtin <ericcurtin17@gmail.com>
3
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published
6
 * by the Free Software Foundation; either version 2 of the licence or (at
7
 * your option) any later version.
8
 *
9
 * This library is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General
15
 * Public License along with this library. If not, see <https://www.gnu.org/licenses/>.
16
 */
17
18
#include "config.h"
19
20
#include "ostree-bootloader-aboot.h"
21
#include "ostree-deployment-private.h"
22
#include "ostree-libarchive-private.h"
23
#include "ostree-sysroot-private.h"
24
#include "otutil.h"
25
#include <sys/mount.h>
26
#include <stdint.h>
27
28
#include <string.h>
29
30
/* This is specific to aboot and zipl today, but in the future we could also
31
 * use it for the grub2-mkconfig case.
32
 */
33
static const char aboot_requires_execute_path[] = "boot/ostree-bootloader-update.stamp";
34
35
struct _OstreeBootloaderAboot
36
{
37
  GObject parent_instance;
38
39
  OstreeSysroot *sysroot;
40
};
41
42
typedef GObjectClass OstreeBootloaderAbootClass;
43
static void _ostree_bootloader_aboot_bootloader_iface_init (OstreeBootloaderInterface *iface);
44
0
G_DEFINE_TYPE_WITH_CODE (OstreeBootloaderAboot, _ostree_bootloader_aboot, G_TYPE_OBJECT,
45
0
                         G_IMPLEMENT_INTERFACE (OSTREE_TYPE_BOOTLOADER,
46
0
                                                _ostree_bootloader_aboot_bootloader_iface_init));
47
0
48
0
static gboolean
49
0
_ostree_bootloader_aboot_query (OstreeBootloader *bootloader, gboolean *out_is_active,
50
0
                                GCancellable *cancellable, GError **error)
51
0
{
52
  /* We don't auto-detect this one; should be explicitly chosen right now.
53
   * see also https://github.com/coreos/coreos-assembler/pull/849
54
   */
55
0
  *out_is_active = FALSE;
56
0
  return TRUE;
57
0
}
58
59
static const char *
60
_ostree_bootloader_aboot_get_name (OstreeBootloader *bootloader)
61
0
{
62
0
  return "aboot";
63
0
}
64
65
static gboolean
66
_ostree_bootloader_aboot_write_config (OstreeBootloader *bootloader, int bootversion,
67
                                       GPtrArray *new_deployments, GCancellable *cancellable,
68
                                       GError **error)
69
0
{
70
0
  OstreeBootloaderAboot *self = OSTREE_BOOTLOADER_ABOOT (bootloader);
71
72
  /* Write our stamp file */
73
0
  if (!glnx_file_replace_contents_at (self->sysroot->sysroot_fd, aboot_requires_execute_path,
74
0
                                      (guint8 *)"", 0, GLNX_FILE_REPLACE_NODATASYNC, cancellable,
75
0
                                      error))
76
0
    return FALSE;
77
78
0
  return TRUE;
79
0
}
80
81
static gboolean
82
_ostree_aboot_get_bls_config (OstreeBootloaderAboot *self, int bootversion, gchar **aboot,
83
                              gchar **abootcfg, gchar **version, gchar **vmlinuz, gchar **initramfs,
84
                              gchar **options, GCancellable *cancellable, GError **error)
85
0
{
86
0
  g_autoptr (GPtrArray) configs = NULL;
87
0
  if (!_ostree_sysroot_read_boot_loader_configs (self->sysroot, bootversion, &configs, cancellable,
88
0
                                                 error))
89
0
    return glnx_prefix_error (error, "aboot: loading bls configs");
90
91
0
  if (!configs || configs->len == 0)
92
0
    return glnx_throw (error, "aboot: no bls config");
93
94
0
  OstreeBootconfigParser *parser = (OstreeBootconfigParser *)g_ptr_array_index (configs, 0);
95
0
  const gchar *val = NULL;
96
97
0
  val = ostree_bootconfig_parser_get (parser, "aboot");
98
0
  if (!val)
99
0
    {
100
0
      return glnx_throw (error, "aboot: no \"aboot\" key in bootloader config");
101
0
    }
102
0
  *aboot = g_strdup (val);
103
104
0
  val = ostree_bootconfig_parser_get (parser, "abootcfg");
105
0
  if (!val)
106
0
    {
107
0
      return glnx_throw (error, "aboot: no \"abootcfg\" key in bootloader config");
108
0
    }
109
0
  *abootcfg = g_strdup (val);
110
111
0
  val = ostree_bootconfig_parser_get (parser, "version");
112
0
  if (!val)
113
0
    return glnx_throw (error, "aboot: no \"version\" key in bootloader config");
114
0
  *version = g_strdup (val);
115
116
0
  val = ostree_bootconfig_parser_get (parser, "linux");
117
0
  if (!val)
118
0
    return glnx_throw (error, "aboot: no \"linux\" key in bootloader config");
119
0
  *vmlinuz = g_build_filename ("/boot", val, NULL);
120
121
0
  val = ostree_bootconfig_parser_get (parser, "initrd");
122
0
  if (!val)
123
0
    return glnx_throw (error, "aboot: no \"initrd\" key in bootloader config");
124
0
  *initramfs = g_build_filename ("/boot", val, NULL);
125
126
0
  val = ostree_bootconfig_parser_get (parser, "options");
127
0
  if (!val)
128
0
    return glnx_throw (error, "aboot: no \"options\" key in bootloader config");
129
0
  *options = g_strdup (val);
130
131
0
  return TRUE;
132
0
}
133
134
static void
135
child_setup_fchdir (gpointer data)
136
0
{
137
0
  int fd = (int)(uintptr_t)data;
138
0
  int rc = fchdir (fd);
139
0
  g_assert (rc == 0);
140
0
}
141
142
static gboolean
143
_ostree_bootloader_aboot_post_bls_sync (OstreeBootloader *bootloader, int bootversion,
144
                                        GCancellable *cancellable, GError **error)
145
0
{
146
0
  OstreeBootloaderAboot *self = OSTREE_BOOTLOADER_ABOOT (bootloader);
147
148
  /* Note that unlike the grub2-mkconfig backend, we make no attempt to
149
   * chroot().
150
   */
151
  // g_assert (self->sysroot->booted_deployment);
152
153
0
  if (!glnx_fstatat_allow_noent (self->sysroot->sysroot_fd, aboot_requires_execute_path, NULL, 0,
154
0
                                 error))
155
0
    return FALSE;
156
157
  /* If there's no stamp file, nothing to do */
158
0
  if (errno == ENOENT)
159
0
    return TRUE;
160
161
0
  g_autofree gchar *aboot = NULL;
162
0
  g_autofree gchar *abootcfg = NULL;
163
0
  g_autofree gchar *version = NULL;
164
0
  g_autofree gchar *vmlinuz = NULL;
165
0
  g_autofree gchar *initramfs = NULL;
166
0
  g_autofree gchar *options = NULL;
167
0
  if (!_ostree_aboot_get_bls_config (self, bootversion, &aboot, &abootcfg, &version, &vmlinuz,
168
0
                                     &initramfs, &options, cancellable, error))
169
0
    return FALSE;
170
171
0
  const char *const aboot_argv[]
172
0
      = { "aboot-deploy", "-r", ".", "-c", abootcfg, "-o", options, aboot, NULL };
173
0
  int estatus;
174
175
0
  if (!g_spawn_sync (NULL, (char **)aboot_argv, NULL, G_SPAWN_SEARCH_PATH, child_setup_fchdir,
176
0
                     (gpointer)(uintptr_t)self->sysroot->sysroot_fd, NULL, NULL, &estatus, error))
177
0
    {
178
0
      return FALSE;
179
0
    }
180
181
0
  if (!g_spawn_check_exit_status (estatus, error))
182
0
    {
183
0
      return FALSE;
184
0
    }
185
186
0
  if (!glnx_unlinkat (self->sysroot->sysroot_fd, aboot_requires_execute_path, 0, error))
187
0
    {
188
0
      return FALSE;
189
0
    }
190
191
0
  return TRUE;
192
0
}
193
194
static void
195
_ostree_bootloader_aboot_finalize (GObject *object)
196
0
{
197
0
  OstreeBootloaderAboot *self = OSTREE_BOOTLOADER_ABOOT (object);
198
199
0
  g_clear_object (&self->sysroot);
200
201
0
  G_OBJECT_CLASS (_ostree_bootloader_aboot_parent_class)->finalize (object);
202
0
}
203
204
void
205
_ostree_bootloader_aboot_init (OstreeBootloaderAboot *self)
206
0
{
207
0
}
208
209
static void
210
_ostree_bootloader_aboot_bootloader_iface_init (OstreeBootloaderInterface *iface)
211
0
{
212
0
  iface->query = _ostree_bootloader_aboot_query;
213
0
  iface->get_name = _ostree_bootloader_aboot_get_name;
214
0
  iface->write_config = _ostree_bootloader_aboot_write_config;
215
0
  iface->post_bls_sync = _ostree_bootloader_aboot_post_bls_sync;
216
0
}
217
218
void
219
_ostree_bootloader_aboot_class_init (OstreeBootloaderAbootClass *class)
220
0
{
221
0
  GObjectClass *object_class = G_OBJECT_CLASS (class);
222
223
0
  object_class->finalize = _ostree_bootloader_aboot_finalize;
224
0
}
225
226
OstreeBootloaderAboot *
227
_ostree_bootloader_aboot_new (OstreeSysroot *sysroot)
228
0
{
229
0
  OstreeBootloaderAboot *self = g_object_new (OSTREE_TYPE_BOOTLOADER_ABOOT, NULL);
230
0
  self->sysroot = g_object_ref (sysroot);
231
0
  return self;
232
0
}