libpriv: Factor out "find kernel/initramfs" code into kernel.[ch]
To support running dracut on the client side, the dracut code needs this, and it makes more sense in kernel.[ch] anyways. I chose to use a GVariant instead of making a custom structure to avoid having to manage custom free funcs. Closes: #566 Approved by: jlebon
This commit is contained in:
parent
178ec03154
commit
16efa12ae0
@ -38,6 +38,183 @@
|
|||||||
#include "rpmostree-bwrap.h"
|
#include "rpmostree-bwrap.h"
|
||||||
#include "rpmostree-util.h"
|
#include "rpmostree-util.h"
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
find_kernel_and_initramfs_in_bootdir (int rootfs_dfd,
|
||||||
|
const char *bootdir,
|
||||||
|
char **out_kernel,
|
||||||
|
char **out_initramfs,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||||
|
glnx_fd_close int dfd = -1;
|
||||||
|
g_autofree char* ret_kernel = NULL;
|
||||||
|
g_autofree char* ret_initramfs = NULL;
|
||||||
|
|
||||||
|
*out_kernel = *out_initramfs = NULL;
|
||||||
|
|
||||||
|
dfd = glnx_opendirat_with_errno (rootfs_dfd, bootdir, FALSE);
|
||||||
|
if (dfd < 0)
|
||||||
|
{
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return TRUE;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glnx_set_error_from_errno (error);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!glnx_dirfd_iterator_init_take_fd (dfd, &dfd_iter, error))
|
||||||
|
return FALSE;
|
||||||
|
dfd = -1;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
struct dirent *dent = NULL;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
|
||||||
|
return FALSE;
|
||||||
|
if (!dent)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (dent->d_type != DT_REG)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
name = dent->d_name;
|
||||||
|
|
||||||
|
/* Current Fedora 23 kernel.spec installs as just vmlinuz */
|
||||||
|
if (strcmp (name, "vmlinuz") == 0 || g_str_has_prefix (name, "vmlinuz-"))
|
||||||
|
{
|
||||||
|
if (ret_kernel)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Multiple vmlinuz- in %s",
|
||||||
|
bootdir);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
ret_kernel = g_strconcat (bootdir, "/", name, NULL);
|
||||||
|
}
|
||||||
|
else if (g_str_has_prefix (name, "initramfs-"))
|
||||||
|
{
|
||||||
|
if (ret_initramfs)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Multiple initramfs- in %s", bootdir);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
ret_initramfs = g_strconcat (bootdir, "/", name, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_kernel = g_steal_pointer (&ret_kernel);
|
||||||
|
*out_initramfs = g_steal_pointer (&ret_initramfs);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given a directory @subpath, find the first child that is a directory,
|
||||||
|
* returning it in @out_subdir. If there are multiple directories,
|
||||||
|
* return an error.
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
find_ensure_one_subdirectory (int rootfs_dfd,
|
||||||
|
const char *subpath,
|
||||||
|
char **out_subdir,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_autofree char *ret_subdir = NULL;
|
||||||
|
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||||
|
|
||||||
|
if (!glnx_dirfd_iterator_init_at (rootfs_dfd, subpath, TRUE, &dfd_iter, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
struct dirent *dent = NULL;
|
||||||
|
|
||||||
|
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
|
||||||
|
return FALSE;
|
||||||
|
if (!dent)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (dent->d_type != DT_DIR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ret_subdir)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Multiple subdirectories found in: %s", subpath);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
ret_subdir = g_strconcat (subpath, "/", dent->d_name, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_subdir = g_steal_pointer (&ret_subdir);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given a root filesystem, return a GVariant of format (sssms):
|
||||||
|
* - kver: uname -r equivalent
|
||||||
|
* - bootdir: Path to the boot directory
|
||||||
|
* - kernel_path: Relative path to kernel
|
||||||
|
* - initramfs_path: Relative path to initramfs (may be NULL if no initramfs)
|
||||||
|
*/
|
||||||
|
GVariant *
|
||||||
|
rpmostree_find_kernel (int rootfs_dfd,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_autofree char* kernel_path = NULL;
|
||||||
|
g_autofree char* initramfs_path = NULL;
|
||||||
|
const char *kver = NULL; /* May point to kver_owned */
|
||||||
|
g_autofree char *kver_owned = NULL;
|
||||||
|
g_autofree char *bootdir = g_strdup ("boot");
|
||||||
|
|
||||||
|
if (!find_kernel_and_initramfs_in_bootdir (rootfs_dfd, bootdir,
|
||||||
|
&kernel_path, &initramfs_path,
|
||||||
|
cancellable, error))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (kernel_path == NULL)
|
||||||
|
{
|
||||||
|
g_autofree char* modversion_dir = NULL;
|
||||||
|
|
||||||
|
if (!find_ensure_one_subdirectory (rootfs_dfd, "usr/lib/modules", &modversion_dir,
|
||||||
|
cancellable, error))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (modversion_dir)
|
||||||
|
{
|
||||||
|
kver = glnx_basename (modversion_dir);
|
||||||
|
bootdir = g_steal_pointer (&modversion_dir);
|
||||||
|
if (!find_kernel_and_initramfs_in_bootdir (rootfs_dfd, bootdir,
|
||||||
|
&kernel_path, &initramfs_path,
|
||||||
|
cancellable, error))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kernel_path == NULL)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Unable to find kernel (vmlinuz) in /boot or /usr/lib/modules (bootdir=%s)", bootdir);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!kver)
|
||||||
|
{
|
||||||
|
const char *kname = glnx_basename (kernel_path);
|
||||||
|
const char *kver_p;
|
||||||
|
|
||||||
|
kver_p = strchr (kname, '-');
|
||||||
|
g_assert (kver_p);
|
||||||
|
kver = kver_owned = g_strdup (kver_p + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_variant_ref_sink (g_variant_new ("(sssms)", kver, bootdir, kernel_path, initramfs_path));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dracut_child_setup (gpointer data)
|
dracut_child_setup (gpointer data)
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,11 @@
|
|||||||
|
|
||||||
#include <ostree.h>
|
#include <ostree.h>
|
||||||
|
|
||||||
|
GVariant *
|
||||||
|
rpmostree_find_kernel (int rootfs_dfd,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
rpmostree_run_dracut (int rootfs_dfd,
|
rpmostree_run_dracut (int rootfs_dfd,
|
||||||
char **argv,
|
char **argv,
|
||||||
|
@ -135,122 +135,6 @@ init_rootfs (int dfd,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
find_kernel_and_initramfs_in_bootdir (int rootfs_dfd,
|
|
||||||
const char *bootdir,
|
|
||||||
char **out_kernel,
|
|
||||||
char **out_initramfs,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
|
||||||
glnx_fd_close int dfd = -1;
|
|
||||||
g_autofree char* ret_kernel = NULL;
|
|
||||||
g_autofree char* ret_initramfs = NULL;
|
|
||||||
|
|
||||||
*out_kernel = *out_initramfs = NULL;
|
|
||||||
|
|
||||||
dfd = glnx_opendirat_with_errno (rootfs_dfd, bootdir, FALSE);
|
|
||||||
if (dfd < 0)
|
|
||||||
{
|
|
||||||
if (errno == ENOENT)
|
|
||||||
return TRUE;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glnx_set_error_from_errno (error);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!glnx_dirfd_iterator_init_take_fd (dfd, &dfd_iter, error))
|
|
||||||
return FALSE;
|
|
||||||
dfd = -1;
|
|
||||||
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
struct dirent *dent = NULL;
|
|
||||||
const char *name;
|
|
||||||
|
|
||||||
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
|
|
||||||
return FALSE;
|
|
||||||
if (!dent)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (dent->d_type != DT_REG)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
name = dent->d_name;
|
|
||||||
|
|
||||||
/* Current Fedora 23 kernel.spec installs as just vmlinuz */
|
|
||||||
if (strcmp (name, "vmlinuz") == 0 || g_str_has_prefix (name, "vmlinuz-"))
|
|
||||||
{
|
|
||||||
if (ret_kernel)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Multiple vmlinuz- in %s",
|
|
||||||
bootdir);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
ret_kernel = g_strconcat (bootdir, "/", name, NULL);
|
|
||||||
}
|
|
||||||
else if (g_str_has_prefix (name, "initramfs-"))
|
|
||||||
{
|
|
||||||
if (ret_initramfs)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Multiple initramfs- in %s", bootdir);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
ret_initramfs = g_strconcat (bootdir, "/", name, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_kernel = g_steal_pointer (&ret_kernel);
|
|
||||||
*out_initramfs = g_steal_pointer (&ret_initramfs);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Given a directory @d, find the first child that is a directory,
|
|
||||||
* returning it in @out_subdir. If there are multiple directories,
|
|
||||||
* return an error.
|
|
||||||
*/
|
|
||||||
static gboolean
|
|
||||||
find_ensure_one_subdirectory (int rootfs_dfd,
|
|
||||||
const char *subpath,
|
|
||||||
char **out_subdir,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
g_autofree char *ret_subdir = NULL;
|
|
||||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
|
||||||
|
|
||||||
if (!glnx_dirfd_iterator_init_at (rootfs_dfd, subpath, TRUE, &dfd_iter, error))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
struct dirent *dent = NULL;
|
|
||||||
|
|
||||||
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
|
|
||||||
return FALSE;
|
|
||||||
if (!dent)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (dent->d_type != DT_DIR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ret_subdir)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Multiple subdirectories found in: %s", subpath);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
ret_subdir = g_strconcat (subpath, "/", dent->d_name, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_subdir = g_steal_pointer (&ret_subdir);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
do_kernel_prep (int rootfs_dfd,
|
do_kernel_prep (int rootfs_dfd,
|
||||||
JsonObject *treefile,
|
JsonObject *treefile,
|
||||||
@ -258,47 +142,24 @@ do_kernel_prep (int rootfs_dfd,
|
|||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
g_autofree char* kernel_path = NULL;
|
g_autoptr(GVariant) kernelstate = NULL;
|
||||||
g_autofree char* initramfs_path = NULL;
|
const char* kernel_path;
|
||||||
|
const char* initramfs_path;
|
||||||
|
const char *kver;
|
||||||
|
const char *bootdir;
|
||||||
const char *boot_checksum_str = NULL;
|
const char *boot_checksum_str = NULL;
|
||||||
g_autoptr(GChecksum) boot_checksum = NULL;
|
g_autoptr(GChecksum) boot_checksum = NULL;
|
||||||
const char *kver = NULL; /* May point to kver_owned */
|
|
||||||
g_autofree char *kver_owned = NULL;
|
|
||||||
g_autofree char *bootdir = g_strdup ("boot");
|
|
||||||
glnx_fd_close int initramfs_tmp_fd = -1;
|
glnx_fd_close int initramfs_tmp_fd = -1;
|
||||||
g_autofree char *initramfs_tmp_path = NULL;
|
g_autofree char *initramfs_tmp_path = NULL;
|
||||||
|
g_autofree char *initramfs_staged_path = NULL;
|
||||||
|
|
||||||
if (!find_kernel_and_initramfs_in_bootdir (rootfs_dfd, bootdir,
|
kernelstate = rpmostree_find_kernel (rootfs_dfd, cancellable, error);
|
||||||
&kernel_path, &initramfs_path,
|
if (!kernelstate)
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
goto out;
|
||||||
|
g_variant_get (kernelstate, "(&s&s&sm&s)",
|
||||||
|
&kver, &bootdir,
|
||||||
|
&kernel_path, &initramfs_path);
|
||||||
|
|
||||||
if (kernel_path == NULL)
|
|
||||||
{
|
|
||||||
g_autofree char* modversion_dir = NULL;
|
|
||||||
|
|
||||||
if (!find_ensure_one_subdirectory (rootfs_dfd, "usr/lib/modules", &modversion_dir,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (modversion_dir)
|
|
||||||
{
|
|
||||||
kver = glnx_basename (modversion_dir);
|
|
||||||
bootdir = g_steal_pointer (&modversion_dir);
|
|
||||||
if (!find_kernel_and_initramfs_in_bootdir (rootfs_dfd, bootdir,
|
|
||||||
&kernel_path, &initramfs_path,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kernel_path == NULL)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Unable to find kernel (vmlinuz) in /boot or /usr/lib/modules (bootdir=%s)", bootdir);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initramfs_path)
|
if (initramfs_path)
|
||||||
{
|
{
|
||||||
g_print ("Removing RPM-generated '%s'\n", initramfs_path);
|
g_print ("Removing RPM-generated '%s'\n", initramfs_path);
|
||||||
@ -306,16 +167,6 @@ do_kernel_prep (int rootfs_dfd,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!kver)
|
|
||||||
{
|
|
||||||
const char *kname = glnx_basename (kernel_path);
|
|
||||||
const char *kver_p;
|
|
||||||
|
|
||||||
kver_p = strchr (kname, '-');
|
|
||||||
g_assert (kver_p);
|
|
||||||
kver = kver_owned = g_strdup (kver_p + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* OSTree needs to own this */
|
/* OSTree needs to own this */
|
||||||
if (!glnx_shutil_rm_rf_at (rootfs_dfd, "boot/loader", cancellable, error))
|
if (!glnx_shutil_rm_rf_at (rootfs_dfd, "boot/loader", cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
@ -364,23 +215,19 @@ do_kernel_prep (int rootfs_dfd,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
{ g_autofree char *initramfs_dest = g_strconcat (bootdir, "/initramfs-", kver, ".img", NULL);
|
initramfs_staged_path = g_strconcat (bootdir, "/initramfs-", kver, ".img", NULL);
|
||||||
|
|
||||||
if (!glnx_link_tmpfile_at (rootfs_dfd, GLNX_LINK_TMPFILE_NOREPLACE,
|
if (!glnx_link_tmpfile_at (rootfs_dfd, GLNX_LINK_TMPFILE_NOREPLACE,
|
||||||
initramfs_tmp_fd, initramfs_tmp_path,
|
initramfs_tmp_fd, initramfs_tmp_path,
|
||||||
rootfs_dfd, initramfs_dest,
|
rootfs_dfd, initramfs_staged_path,
|
||||||
error))
|
error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
g_free (initramfs_path);
|
|
||||||
initramfs_path = g_steal_pointer (&initramfs_dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
boot_checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
boot_checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
||||||
if (!_rpmostree_util_update_checksum_from_file (boot_checksum, rootfs_dfd, kernel_path,
|
if (!_rpmostree_util_update_checksum_from_file (boot_checksum, rootfs_dfd, kernel_path,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
if (!_rpmostree_util_update_checksum_from_file (boot_checksum, rootfs_dfd, initramfs_path,
|
if (!_rpmostree_util_update_checksum_from_file (boot_checksum, rootfs_dfd, initramfs_staged_path,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -390,7 +237,7 @@ do_kernel_prep (int rootfs_dfd,
|
|||||||
g_autofree char *new_kernel_path =
|
g_autofree char *new_kernel_path =
|
||||||
g_strconcat (bootdir, "/", glnx_basename (kernel_path), "-", boot_checksum_str, NULL);
|
g_strconcat (bootdir, "/", glnx_basename (kernel_path), "-", boot_checksum_str, NULL);
|
||||||
g_autofree char *new_initramfs_path =
|
g_autofree char *new_initramfs_path =
|
||||||
g_strconcat (bootdir, "/", glnx_basename (initramfs_path), "-", boot_checksum_str, NULL);
|
g_strconcat (bootdir, "/", glnx_basename (initramfs_staged_path), "-", boot_checksum_str, NULL);
|
||||||
|
|
||||||
if (renameat (rootfs_dfd, kernel_path, rootfs_dfd, new_kernel_path) < 0)
|
if (renameat (rootfs_dfd, kernel_path, rootfs_dfd, new_kernel_path) < 0)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user