grub2: Use g_spawn_sync() rather than GSubprocess to avoid SIGCHLD
Due to the async nature of `GSubprocess` it grabs `SIGCHLD` which affects other software which might be using libostree, such as QtOTA. Closes: https://github.com/ostreedev/ostree/issues/696 Closes: #702 Approved by: jlebon
This commit is contained in:
parent
36b28cb4d2
commit
9695c47684
|
|
@ -239,12 +239,26 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *root;
|
||||||
|
const char *bootversion_str;
|
||||||
|
gboolean is_efi;
|
||||||
|
} Grub2ChildSetupData;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
grub2_child_setup (gpointer user_data)
|
grub2_child_setup (gpointer user_data)
|
||||||
{
|
{
|
||||||
const char *root = user_data;
|
Grub2ChildSetupData *cdata = user_data;
|
||||||
|
|
||||||
if (chdir (root) != 0)
|
setenv ("_OSTREE_GRUB2_BOOTVERSION", cdata->bootversion_str, TRUE);
|
||||||
|
/* We have to pass our state to the child */
|
||||||
|
if (cdata->is_efi)
|
||||||
|
setenv ("_OSTREE_GRUB2_IS_EFI", "1", TRUE);
|
||||||
|
|
||||||
|
if (!cdata->root)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (chdir (cdata->root) != 0)
|
||||||
{
|
{
|
||||||
perror ("chdir");
|
perror ("chdir");
|
||||||
_exit (1);
|
_exit (1);
|
||||||
|
|
@ -268,7 +282,7 @@ grub2_child_setup (gpointer user_data)
|
||||||
_exit (1);
|
_exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mount (root, "/", NULL, MS_MOVE, NULL) < 0)
|
if (mount (cdata->root, "/", NULL, MS_MOVE, NULL) < 0)
|
||||||
{
|
{
|
||||||
perror ("failed to MS_MOVE to /");
|
perror ("failed to MS_MOVE to /");
|
||||||
_exit (1);
|
_exit (1);
|
||||||
|
|
@ -290,14 +304,15 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader,
|
||||||
OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader);
|
OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader);
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
g_autoptr(GFile) new_config_path = NULL;
|
g_autoptr(GFile) new_config_path = NULL;
|
||||||
GSubprocessFlags subp_flags = 0;
|
|
||||||
glnx_unref_object GSubprocessLauncher *launcher = NULL;
|
|
||||||
glnx_unref_object GSubprocess *proc = NULL;
|
|
||||||
g_autofree char *bootversion_str = g_strdup_printf ("%u", (guint)bootversion);
|
g_autofree char *bootversion_str = g_strdup_printf ("%u", (guint)bootversion);
|
||||||
g_autoptr(GFile) config_path_efi_dir = NULL;
|
g_autoptr(GFile) config_path_efi_dir = NULL;
|
||||||
g_autofree char *grub2_mkconfig_chroot = NULL;
|
g_autofree char *grub2_mkconfig_chroot = NULL;
|
||||||
gboolean use_system_grub2_mkconfig = TRUE;
|
gboolean use_system_grub2_mkconfig = TRUE;
|
||||||
const gchar *grub_exec = NULL;
|
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, };
|
||||||
|
|
||||||
#ifdef USE_BUILTIN_GRUB2_MKCONFIG
|
#ifdef USE_BUILTIN_GRUB2_MKCONFIG
|
||||||
use_system_grub2_mkconfig = FALSE;
|
use_system_grub2_mkconfig = FALSE;
|
||||||
|
|
@ -354,22 +369,15 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader,
|
||||||
bootversion);
|
bootversion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
grub_argv[0] = grub_exec;
|
||||||
|
grub_argv[2] = gs_file_get_path_cached (new_config_path);
|
||||||
|
|
||||||
if (!g_getenv ("OSTREE_DEBUG_GRUB2"))
|
if (!g_getenv ("OSTREE_DEBUG_GRUB2"))
|
||||||
subp_flags |= (G_SUBPROCESS_FLAGS_STDOUT_SILENCE | G_SUBPROCESS_FLAGS_STDERR_SILENCE);
|
grub_spawnflags |= G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL;
|
||||||
|
cdata.root = grub2_mkconfig_chroot;
|
||||||
launcher = g_subprocess_launcher_new (subp_flags);
|
cdata.bootversion_str = bootversion_str;
|
||||||
g_subprocess_launcher_setenv (launcher, "_OSTREE_GRUB2_BOOTVERSION", bootversion_str, TRUE);
|
cdata.is_efi = self->is_efi;
|
||||||
/* We have to pass our state to the child */
|
/* Note in older versions of the grub2 package, this script doesn't even try
|
||||||
if (self->is_efi)
|
|
||||||
g_subprocess_launcher_setenv (launcher, "_OSTREE_GRUB2_IS_EFI", "1", TRUE);
|
|
||||||
|
|
||||||
/* We need to chroot() if we're not in /. This assumes our caller has
|
|
||||||
* set up the bind mounts outside.
|
|
||||||
*/
|
|
||||||
if (grub2_mkconfig_chroot != NULL)
|
|
||||||
g_subprocess_launcher_set_child_setup (launcher, grub2_child_setup, grub2_mkconfig_chroot, NULL);
|
|
||||||
|
|
||||||
/* In the current Fedora grub2 package, this script doesn't even try
|
|
||||||
to be atomic; it just does:
|
to be atomic; it just does:
|
||||||
|
|
||||||
cat ${grub_cfg}.new > ${grub_cfg}
|
cat ${grub_cfg}.new > ${grub_cfg}
|
||||||
|
|
@ -377,13 +385,15 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader,
|
||||||
|
|
||||||
Upstream is fixed though.
|
Upstream is fixed though.
|
||||||
*/
|
*/
|
||||||
proc = g_subprocess_launcher_spawn (launcher, error,
|
if (!g_spawn_sync (NULL, (char**)grub_argv, NULL, grub_spawnflags,
|
||||||
grub_exec, "-o",
|
grub2_child_setup, &cdata, NULL, NULL,
|
||||||
gs_file_get_path_cached (new_config_path),
|
&grub2_estatus, error))
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (!g_subprocess_wait_check (proc, cancellable, error))
|
|
||||||
goto out;
|
goto out;
|
||||||
|
if (!g_spawn_check_exit_status (grub2_estatus, error))
|
||||||
|
{
|
||||||
|
g_prefix_error (error, "%s: ", grub_argv[0]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Now let's fdatasync() for the new file */
|
/* Now let's fdatasync() for the new file */
|
||||||
{ glnx_fd_close int new_config_fd = open (gs_file_get_path_cached (new_config_path), O_RDONLY | O_CLOEXEC);
|
{ glnx_fd_close int new_config_fd = open (gs_file_get_path_cached (new_config_path), O_RDONLY | O_CLOEXEC);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue