lib/grub2: Port some to new code style

I resisted trying to do anything invasive here like fd-relative porting as our
coverage is weak. But this was all straightforward porting to decl-after-stmt
style.

Closes: #1153
Approved by: jlebon
This commit is contained in:
Colin Walters 2017-09-07 21:46:10 -04:00 committed by Atomic Bot
parent 43c78c9006
commit 6be4dfe66e
1 changed files with 57 additions and 70 deletions

View File

@ -75,18 +75,17 @@ _ostree_bootloader_grub2_query (OstreeBootloader *bootloader,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
gboolean ret = FALSE;
OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader); OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader);
g_autoptr(GFile) efi_basedir = NULL;
/* Look for the BIOS path first */
if (g_file_query_exists (self->config_path_bios, NULL)) if (g_file_query_exists (self->config_path_bios, NULL))
{ {
/* If we found it, we're done */
*out_is_active = TRUE; *out_is_active = TRUE;
ret = TRUE; return TRUE;
goto out;
} }
efi_basedir = g_file_resolve_relative_path (self->sysroot->path, "boot/efi/EFI"); g_autoptr(GFile) efi_basedir = g_file_resolve_relative_path (self->sysroot->path, "boot/efi/EFI");
g_clear_object (&self->config_path_efi); g_clear_object (&self->config_path_efi);
@ -98,17 +97,16 @@ _ostree_bootloader_grub2_query (OstreeBootloader *bootloader,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable, error); cancellable, error);
if (!direnum) if (!direnum)
goto out; return FALSE;
while (TRUE) while (TRUE)
{ {
GFileInfo *file_info; GFileInfo *file_info;
const char *fname; const char *fname;
g_autofree char *subdir_grub_cfg = NULL;
if (!g_file_enumerator_iterate (direnum, &file_info, NULL, if (!g_file_enumerator_iterate (direnum, &file_info, NULL,
cancellable, error)) cancellable, error))
goto out; return FALSE;
if (file_info == NULL) if (file_info == NULL)
break; break;
@ -119,8 +117,9 @@ _ostree_bootloader_grub2_query (OstreeBootloader *bootloader,
if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
continue; continue;
subdir_grub_cfg = g_build_filename (gs_file_get_path_cached (efi_basedir), fname, "grub.cfg", NULL); g_autofree char *subdir_grub_cfg =
g_build_filename (gs_file_get_path_cached (efi_basedir), fname, "grub.cfg", NULL);
if (g_file_test (subdir_grub_cfg, G_FILE_TEST_EXISTS)) if (g_file_test (subdir_grub_cfg, G_FILE_TEST_EXISTS))
{ {
self->config_path_efi = g_file_new_for_path (subdir_grub_cfg); self->config_path_efi = g_file_new_for_path (subdir_grub_cfg);
@ -128,20 +127,18 @@ _ostree_bootloader_grub2_query (OstreeBootloader *bootloader,
} }
} }
/* If we found the EFI path, we're done */
if (self->config_path_efi) if (self->config_path_efi)
{ {
self->is_efi = TRUE; self->is_efi = TRUE;
*out_is_active = TRUE; *out_is_active = TRUE;
ret = TRUE; return TRUE;
goto out;
} }
} }
else else
*out_is_active = FALSE; *out_is_active = FALSE;
ret = TRUE; return TRUE;
out:
return ret;
} }
static const char * static const char *
@ -150,6 +147,10 @@ _ostree_bootloader_grub2_get_name (OstreeBootloader *bootloader)
return "grub2"; return "grub2";
} }
/* This implementation is quite complex; see this issue for
* a starting point:
* https://github.com/ostreedev/ostree/issues/717
*/
gboolean gboolean
_ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot, _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot,
int bootversion, int bootversion,
@ -157,13 +158,6 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
gboolean ret = FALSE;
g_autoptr(GString) output = g_string_new ("");
g_autoptr(GOutputStream) out_stream = NULL;
g_autoptr(GPtrArray) loader_configs = NULL;
guint i;
gsize bytes_written;
gboolean is_efi;
/* So... yeah. Just going to hardcode these. */ /* So... yeah. Just going to hardcode these. */
static const char hardcoded_video[] = "load_video\n" static const char hardcoded_video[] = "load_video\n"
"set gfxpayload=keep\n"; "set gfxpayload=keep\n";
@ -178,16 +172,18 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot
g_assert (grub2_prepare_root_cache != NULL); g_assert (grub2_prepare_root_cache != NULL);
/* Passed from the parent */ /* Passed from the parent */
is_efi = g_getenv ("_OSTREE_GRUB2_IS_EFI") != NULL; gboolean is_efi = g_getenv ("_OSTREE_GRUB2_IS_EFI") != NULL;
out_stream = g_unix_output_stream_new (target_fd, FALSE); g_autoptr(GOutputStream) out_stream = g_unix_output_stream_new (target_fd, FALSE);
g_autoptr(GPtrArray) loader_configs = NULL;
if (!_ostree_sysroot_read_boot_loader_configs (sysroot, bootversion, if (!_ostree_sysroot_read_boot_loader_configs (sysroot, bootversion,
&loader_configs, &loader_configs,
cancellable, error)) cancellable, error))
goto out; return FALSE;
for (i = 0; i < loader_configs->len; i++) g_autoptr(GString) output = g_string_new ("");
for (guint i = 0; i < loader_configs->len; i++)
{ {
OstreeBootconfigParser *config = loader_configs->pdata[i]; OstreeBootconfigParser *config = loader_configs->pdata[i];
const char *title; const char *title;
@ -217,13 +213,9 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot
g_string_append (output, hardcoded_insmods); g_string_append (output, hardcoded_insmods);
g_string_append (output, grub2_prepare_root_cache); g_string_append (output, grub2_prepare_root_cache);
g_string_append_c (output, '\n'); g_string_append_c (output, '\n');
if (!kernel) if (!kernel)
{ return glnx_throw (error, "No \"linux\" key in bootloader config");
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No \"linux\" key in bootloader config");
goto out;
}
g_string_append (output, "linux"); g_string_append (output, "linux");
if (is_efi) if (is_efi)
g_string_append (output, GRUB2_EFI_SUFFIX); g_string_append (output, GRUB2_EFI_SUFFIX);
@ -256,13 +248,12 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot
g_string_append (output, "}\n"); g_string_append (output, "}\n");
} }
gsize bytes_written;
if (!g_output_stream_write_all (out_stream, output->str, output->len, if (!g_output_stream_write_all (out_stream, output->str, output->len,
&bytes_written, cancellable, error)) &bytes_written, cancellable, error))
goto out; return FALSE;
ret = TRUE; return TRUE;
out:
return ret;
} }
typedef struct { typedef struct {
@ -271,19 +262,24 @@ typedef struct {
gboolean is_efi; gboolean is_efi;
} Grub2ChildSetupData; } Grub2ChildSetupData;
/* Post-fork, pre-exec child setup for grub2-mkconfig */
static void static void
grub2_child_setup (gpointer user_data) grub2_child_setup (gpointer user_data)
{ {
Grub2ChildSetupData *cdata = user_data; Grub2ChildSetupData *cdata = user_data;
setenv ("_OSTREE_GRUB2_BOOTVERSION", cdata->bootversion_str, TRUE); setenv ("_OSTREE_GRUB2_BOOTVERSION", cdata->bootversion_str, TRUE);
/* We have to pass our state to the child */ /* We have to pass our state (whether or not we're using EFI) to the child */
if (cdata->is_efi) if (cdata->is_efi)
setenv ("_OSTREE_GRUB2_IS_EFI", "1", TRUE); setenv ("_OSTREE_GRUB2_IS_EFI", "1", TRUE);
/* Everything below this is dealing with the chroot case; if
* we're not doing that, return early.
*/
if (!cdata->root) if (!cdata->root)
return; return;
/* TODO: investigate replacing this with bwrap */
if (chdir (cdata->root) != 0) if (chdir (cdata->root) != 0)
{ {
perror ("chdir"); perror ("chdir");
@ -321,6 +317,7 @@ grub2_child_setup (gpointer user_data)
} }
} }
/* Main entrypoint for writing GRUB configuration. */
static gboolean static gboolean
_ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader,
int bootversion, int bootversion,
@ -328,23 +325,13 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader,
GError **error) GError **error)
{ {
OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader); OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader);
gboolean ret = FALSE;
g_autoptr(GFile) new_config_path = NULL;
g_autofree char *bootversion_str = g_strdup_printf ("%u", (guint)bootversion);
g_autoptr(GFile) config_path_efi_dir = NULL;
g_autofree char *grub2_mkconfig_chroot = NULL;
gboolean use_system_grub2_mkconfig = TRUE;
const gchar *grub_exec = NULL;
const char *grub_argv[4] = { NULL, "-o", NULL, NULL};
GSpawnFlags grub_spawnflags = G_SPAWN_SEARCH_PATH;
int grub2_estatus;
Grub2ChildSetupData cdata = { NULL, };
/* Autotests can set this envvar to select which code path to test, useful for OS installers as well */
gboolean use_system_grub2_mkconfig = TRUE;
#ifdef USE_BUILTIN_GRUB2_MKCONFIG #ifdef USE_BUILTIN_GRUB2_MKCONFIG
use_system_grub2_mkconfig = FALSE; use_system_grub2_mkconfig = FALSE;
#endif #endif
/* Autotests can set this envvar to select which code path to test, useful for OS installers as well */ const gchar *grub_exec = g_getenv ("OSTREE_GRUB2_EXEC");
grub_exec = g_getenv ("OSTREE_GRUB2_EXEC");
if (grub_exec) if (grub_exec)
{ {
if (g_str_has_suffix (grub_exec, GRUB2_MKCONFIG_PATH)) if (g_str_has_suffix (grub_exec, GRUB2_MKCONFIG_PATH))
@ -355,6 +342,7 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader,
else else
grub_exec = use_system_grub2_mkconfig ? GRUB2_MKCONFIG_PATH : TARGET_PREFIX "/lib/ostree/ostree-grub-generator"; grub_exec = use_system_grub2_mkconfig ? GRUB2_MKCONFIG_PATH : TARGET_PREFIX "/lib/ostree/ostree-grub-generator";
g_autofree char *grub2_mkconfig_chroot = NULL;
if (use_system_grub2_mkconfig && ostree_sysroot_get_booted_deployment (self->sysroot) == NULL if (use_system_grub2_mkconfig && ostree_sysroot_get_booted_deployment (self->sysroot) == NULL
&& g_file_has_parent (self->sysroot->path, NULL)) && g_file_has_parent (self->sysroot->path, NULL))
{ {
@ -381,13 +369,15 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader,
grub2_mkconfig_chroot = g_file_get_path (tool_deployment_root); grub2_mkconfig_chroot = g_file_get_path (tool_deployment_root);
} }
g_autoptr(GFile) new_config_path = NULL;
g_autoptr(GFile) config_path_efi_dir = NULL;
if (self->is_efi) if (self->is_efi)
{ {
config_path_efi_dir = g_file_get_parent (self->config_path_efi); config_path_efi_dir = g_file_get_parent (self->config_path_efi);
new_config_path = g_file_get_child (config_path_efi_dir, "grub.cfg.new"); new_config_path = g_file_get_child (config_path_efi_dir, "grub.cfg.new");
/* We use grub2-mkconfig to write to a temporary file first */ /* We use grub2-mkconfig to write to a temporary file first */
if (!ot_gfile_ensure_unlinked (new_config_path, cancellable, error)) if (!ot_gfile_ensure_unlinked (new_config_path, cancellable, error))
goto out; return FALSE;
} }
else else
{ {
@ -395,12 +385,16 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader,
bootversion); bootversion);
} }
const char *grub_argv[4] = { NULL, "-o", NULL, NULL};
Grub2ChildSetupData cdata = { NULL, };
grub_argv[0] = grub_exec; grub_argv[0] = grub_exec;
grub_argv[2] = gs_file_get_path_cached (new_config_path); grub_argv[2] = gs_file_get_path_cached (new_config_path);
GSpawnFlags grub_spawnflags = G_SPAWN_SEARCH_PATH;
if (!g_getenv ("OSTREE_DEBUG_GRUB2")) if (!g_getenv ("OSTREE_DEBUG_GRUB2"))
grub_spawnflags |= G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL; grub_spawnflags |= G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL;
cdata.root = grub2_mkconfig_chroot; cdata.root = grub2_mkconfig_chroot;
g_autofree char *bootversion_str = g_strdup_printf ("%u", (guint)bootversion);
cdata.bootversion_str = bootversion_str; cdata.bootversion_str = bootversion_str;
cdata.is_efi = self->is_efi; cdata.is_efi = self->is_efi;
/* Note in older versions of the grub2 package, this script doesn't even try /* Note in older versions of the grub2 package, this script doesn't even try
@ -411,54 +405,47 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader,
Upstream is fixed though. Upstream is fixed though.
*/ */
int grub2_estatus;
if (!g_spawn_sync (NULL, (char**)grub_argv, NULL, grub_spawnflags, if (!g_spawn_sync (NULL, (char**)grub_argv, NULL, grub_spawnflags,
grub2_child_setup, &cdata, NULL, NULL, grub2_child_setup, &cdata, NULL, NULL,
&grub2_estatus, error)) &grub2_estatus, error))
goto out; return FALSE;
if (!g_spawn_check_exit_status (grub2_estatus, error)) if (!g_spawn_check_exit_status (grub2_estatus, error))
{ {
g_prefix_error (error, "%s: ", grub_argv[0]); g_prefix_error (error, "%s: ", grub_argv[0]);
goto out; return FALSE;
} }
/* Now let's fdatasync() for the new file */ /* Now let's fdatasync() for the new file */
{ glnx_fd_close int new_config_fd = -1; { glnx_fd_close int new_config_fd = -1;
if (!glnx_openat_rdonly (AT_FDCWD, gs_file_get_path_cached (new_config_path), TRUE, &new_config_fd, error)) if (!glnx_openat_rdonly (AT_FDCWD, gs_file_get_path_cached (new_config_path), TRUE, &new_config_fd, error))
goto out; return FALSE;
if (fdatasync (new_config_fd) < 0) if (fdatasync (new_config_fd) < 0)
{ return glnx_throw_errno_prefix (error, "fdatasync");
(void)glnx_throw_errno_prefix (error, "fdatasync");
goto out;
}
} }
if (self->is_efi) if (self->is_efi)
{ {
g_autoptr(GFile) config_path_efi_old = g_file_get_child (config_path_efi_dir, "grub.cfg.old"); g_autoptr(GFile) config_path_efi_old = g_file_get_child (config_path_efi_dir, "grub.cfg.old");
/* copy current to old */ /* copy current to old */
if (!ot_gfile_ensure_unlinked (config_path_efi_old, cancellable, error)) if (!ot_gfile_ensure_unlinked (config_path_efi_old, cancellable, error))
goto out; return FALSE;
if (!g_file_copy (self->config_path_efi, config_path_efi_old, if (!g_file_copy (self->config_path_efi, config_path_efi_old,
G_FILE_COPY_OVERWRITE, cancellable, NULL, NULL, error)) G_FILE_COPY_OVERWRITE, cancellable, NULL, NULL, error))
goto out; return FALSE;
/* NOTE: NON-ATOMIC REPLACEMENT; WE can't do anything else on FAT; /* NOTE: NON-ATOMIC REPLACEMENT; WE can't do anything else on FAT;
* see https://bugzilla.gnome.org/show_bug.cgi?id=724246 * see https://bugzilla.gnome.org/show_bug.cgi?id=724246
*/ */
if (!ot_gfile_ensure_unlinked (self->config_path_efi, cancellable, error)) if (!ot_gfile_ensure_unlinked (self->config_path_efi, cancellable, error))
goto out; return FALSE;
if (rename (gs_file_get_path_cached (new_config_path), gs_file_get_path_cached (self->config_path_efi)) < 0) if (rename (gs_file_get_path_cached (new_config_path), gs_file_get_path_cached (self->config_path_efi)) < 0)
{ return glnx_throw_errno_prefix (error, "rename");
glnx_set_error_from_errno (error);
goto out;
}
} }
ret = TRUE; return TRUE;
out:
return ret;
} }
static gboolean static gboolean