The current code checks if /boot/uEnv.txt is a symlink to decice if sysroot requires u-boot support. Why this is bad: There are 2 ways to provide a custom env to u-boot from user space: 1) A compiled binary that is sourced from u-boot. 2) A text file (usually /uEnv.txt) that is imported into env from u-boot. The current OSTree u-boot integration code was designed with the 1st case in mind. Many bootscripts provided by an embedded device vendors expect to find uEnv.txt in the top level directory, it is often hardcoded when building u-boot and is difficult to change later on. Or in other cases it is stored in read-only memory so changing it would require re-flushing boot loader with a new env. So the issue here is that OSTree's and vendor uEnv.txt want to exist and the same path and OSTree would throw away any changes added to /uEnv.txt by user on the next upgrade/deploy. This patch "hides" away the OSTree's env file loader/uEnv.txt from users who are used to edditing uEnv.txt at the top level directory. Now to add OSTree support on such boards you can simply add a custom logic in uEnv.txt that loads ostree env from /loader/uEnv.txt This change is backward compatible with the previous ostree releases and solves the issue described in: https://bugzilla.gnome.org/show_bug.cgi?id=755787
183 lines
6.2 KiB
C
183 lines
6.2 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
|
*
|
|
* Copyright (C) 2013 Collabora Ltd
|
|
*
|
|
* Based on ot-bootloader-syslinux.c by Colin Walters <walters@verbum.org>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published
|
|
* by the Free Software Foundation; either version 2 of the licence or (at
|
|
* your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General
|
|
* Public License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*
|
|
* Author: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "ostree-sysroot-private.h"
|
|
#include "ostree-bootloader-uboot.h"
|
|
#include "otutil.h"
|
|
|
|
#include <string.h>
|
|
|
|
struct _OstreeBootloaderUboot
|
|
{
|
|
GObject parent_instance;
|
|
|
|
OstreeSysroot *sysroot;
|
|
GFile *config_path;
|
|
};
|
|
|
|
typedef GObjectClass OstreeBootloaderUbootClass;
|
|
|
|
static void _ostree_bootloader_uboot_bootloader_iface_init (OstreeBootloaderInterface *iface);
|
|
G_DEFINE_TYPE_WITH_CODE (OstreeBootloaderUboot, _ostree_bootloader_uboot, G_TYPE_OBJECT,
|
|
G_IMPLEMENT_INTERFACE (OSTREE_TYPE_BOOTLOADER, _ostree_bootloader_uboot_bootloader_iface_init));
|
|
|
|
static gboolean
|
|
_ostree_bootloader_uboot_query (OstreeBootloader *bootloader,
|
|
gboolean *out_is_active,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (bootloader);
|
|
|
|
*out_is_active = g_file_query_file_type (self->config_path, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL) == G_FILE_TYPE_REGULAR;
|
|
return TRUE;
|
|
}
|
|
|
|
static const char *
|
|
_ostree_bootloader_uboot_get_name (OstreeBootloader *bootloader)
|
|
{
|
|
return "U-Boot";
|
|
}
|
|
|
|
static gboolean
|
|
create_config_from_boot_loader_entries (OstreeBootloaderUboot *self,
|
|
int bootversion,
|
|
GPtrArray *new_lines,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GPtrArray) boot_loader_configs = NULL;
|
|
OstreeBootconfigParser *config;
|
|
const char *val;
|
|
|
|
if (!_ostree_sysroot_read_boot_loader_configs (self->sysroot, bootversion, &boot_loader_configs,
|
|
cancellable, error))
|
|
return FALSE;
|
|
|
|
/* U-Boot doesn't support a menu so just pick the first one since the list is ordered */
|
|
config = boot_loader_configs->pdata[0];
|
|
|
|
val = ostree_bootconfig_parser_get (config, "linux");
|
|
if (!val)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"No \"linux\" key in bootloader config");
|
|
return FALSE;
|
|
}
|
|
g_ptr_array_add (new_lines, g_strdup_printf ("kernel_image=%s", val));
|
|
|
|
val = ostree_bootconfig_parser_get (config, "initrd");
|
|
if (val)
|
|
g_ptr_array_add (new_lines, g_strdup_printf ("ramdisk_image=%s", val));
|
|
|
|
val = ostree_bootconfig_parser_get (config, "options");
|
|
if (val)
|
|
g_ptr_array_add (new_lines, g_strdup_printf ("bootargs=%s", val));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
_ostree_bootloader_uboot_write_config (OstreeBootloader *bootloader,
|
|
int bootversion,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (bootloader);
|
|
g_autoptr(GFile) new_config_path = NULL;
|
|
g_autofree char *config_contents = NULL;
|
|
g_autofree char *new_config_contents = NULL;
|
|
g_autoptr(GPtrArray) new_lines = NULL;
|
|
|
|
/* This should follow the symbolic link to the current bootversion. */
|
|
config_contents = gs_file_load_contents_utf8 (self->config_path, cancellable, error);
|
|
if (!config_contents)
|
|
return FALSE;
|
|
|
|
new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/uEnv.txt",
|
|
bootversion);
|
|
|
|
new_lines = g_ptr_array_new_with_free_func (g_free);
|
|
|
|
if (!create_config_from_boot_loader_entries (self, bootversion, new_lines,
|
|
cancellable, error))
|
|
return FALSE;
|
|
|
|
new_config_contents = _ostree_sysroot_join_lines (new_lines);
|
|
{
|
|
g_autoptr(GBytes) new_config_contents_bytes =
|
|
g_bytes_new_static (new_config_contents,
|
|
strlen (new_config_contents));
|
|
|
|
if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes,
|
|
cancellable, error))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
_ostree_bootloader_uboot_finalize (GObject *object)
|
|
{
|
|
OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (object);
|
|
|
|
g_clear_object (&self->sysroot);
|
|
g_clear_object (&self->config_path);
|
|
|
|
G_OBJECT_CLASS (_ostree_bootloader_uboot_parent_class)->finalize (object);
|
|
}
|
|
|
|
void
|
|
_ostree_bootloader_uboot_init (OstreeBootloaderUboot *self)
|
|
{
|
|
}
|
|
|
|
static void
|
|
_ostree_bootloader_uboot_bootloader_iface_init (OstreeBootloaderInterface *iface)
|
|
{
|
|
iface->query = _ostree_bootloader_uboot_query;
|
|
iface->get_name = _ostree_bootloader_uboot_get_name;
|
|
iface->write_config = _ostree_bootloader_uboot_write_config;
|
|
}
|
|
|
|
void
|
|
_ostree_bootloader_uboot_class_init (OstreeBootloaderUbootClass *class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
|
|
|
object_class->finalize = _ostree_bootloader_uboot_finalize;
|
|
}
|
|
|
|
OstreeBootloaderUboot *
|
|
_ostree_bootloader_uboot_new (OstreeSysroot *sysroot)
|
|
{
|
|
OstreeBootloaderUboot *self = g_object_new (OSTREE_TYPE_BOOTLOADER_UBOOT, NULL);
|
|
self->sysroot = g_object_ref (sysroot);
|
|
self->config_path = g_file_resolve_relative_path (self->sysroot->path, "boot/loader/uEnv.txt");
|
|
return self;
|
|
}
|