diff --git a/Makefile-libpriv.am b/Makefile-libpriv.am index 52bb9f29..d19f5e05 100644 --- a/Makefile-libpriv.am +++ b/Makefile-libpriv.am @@ -32,6 +32,8 @@ librpmostreepriv_la_SOURCES = \ src/libpriv/rpmostree-core.h \ src/libpriv/rpmostree-bwrap.c \ src/libpriv/rpmostree-bwrap.h \ + src/libpriv/rpmostree-kernel.c \ + src/libpriv/rpmostree-kernel.h \ src/libpriv/rpmostree-scripts.c \ src/libpriv/rpmostree-scripts.h \ src/libpriv/rpmostree-refsack.h \ diff --git a/src/libpriv/rpmostree-kernel.c b/src/libpriv/rpmostree-kernel.c new file mode 100644 index 00000000..39f5eaff --- /dev/null +++ b/src/libpriv/rpmostree-kernel.c @@ -0,0 +1,125 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2013,2014,2017 Colin Walters + * + * 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. + */ + +#include "config.h" + +#include "string.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rpmostree-kernel.h" +#include "rpmostree-bwrap.h" +#include "rpmostree-util.h" + +static void +dracut_child_setup (gpointer data) +{ + int fd = GPOINTER_TO_INT (data); + + /* Move the tempfile fd to 3 (and without the cloexec flag) */ + if (dup2 (fd, 3) < 0) + err (1, "dup2"); +} + +gboolean +rpmostree_run_dracut (int rootfs_dfd, + char **argv, + int *out_initramfs_tmpfd, + char **out_initramfs_tmppath, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + /* Shell wrapper around dracut to write to the O_TMPFILE fd; + * at some point in the future we should add --fd X instead of -f + * to dracut. + */ + static const char rpmostree_dracut_wrapper_path[] = "usr/bin/rpmostree-dracut-wrapper"; + /* This also hardcodes a few arguments */ + static const char rpmostree_dracut_wrapper[] = + "#!/usr/bin/bash\n" + "set -euo pipefail\n" + "extra_argv=; if (dracut --help; true) | grep -q -e --reproducible; then extra_argv=\"--reproducible --gzip\"; fi\n" + "dracut $extra_argv -v --add ostree --tmpdir=/tmp -f /tmp/initramfs.img \"$@\"\n" + "cat /tmp/initramfs.img >/proc/self/fd/3\n"; + glnx_fd_close int tmp_fd = -1; + g_autofree char *tmpfile_path = NULL; + g_autoptr(RpmOstreeBwrap) bwrap = NULL; + + /* First tempfile is just our shell script */ + if (!glnx_open_tmpfile_linkable_at (rootfs_dfd, "usr/bin", + O_RDWR | O_CLOEXEC, + &tmp_fd, &tmpfile_path, + error)) + goto out; + if (glnx_loop_write (tmp_fd, rpmostree_dracut_wrapper, sizeof (rpmostree_dracut_wrapper)) < 0 + || fchmod (tmp_fd, 0755) < 0) + { + glnx_set_error_from_errno (error); + goto out; + } + + if (!glnx_link_tmpfile_at (rootfs_dfd, GLNX_LINK_TMPFILE_NOREPLACE, + tmp_fd, tmpfile_path, rootfs_dfd, rpmostree_dracut_wrapper_path, + error)) + goto out; + /* We need to close the writable FD now to be able to exec it */ + close (tmp_fd); tmp_fd = -1; + + /* Second tempfile is the initramfs contents */ + if (!glnx_open_tmpfile_linkable_at (rootfs_dfd, "tmp", + O_WRONLY | O_CLOEXEC, + &tmp_fd, &tmpfile_path, + error)) + goto out; + + bwrap = rpmostree_bwrap_new (rootfs_dfd, RPMOSTREE_BWRAP_IMMUTABLE, error, NULL); + if (!bwrap) + return FALSE; + + /* Set up argv and run */ + rpmostree_bwrap_append_child_argv (bwrap, (char*)glnx_basename (rpmostree_dracut_wrapper_path), NULL); + for (char **iter = argv; iter && *iter; iter++) + rpmostree_bwrap_append_child_argv (bwrap, *iter, NULL); + + rpmostree_bwrap_set_child_setup (bwrap, dracut_child_setup, GINT_TO_POINTER (tmp_fd)); + + if (!rpmostree_bwrap_run (bwrap, error)) + goto out; + + ret = TRUE; + *out_initramfs_tmpfd = tmp_fd; tmp_fd = -1; + *out_initramfs_tmppath = g_steal_pointer (&tmpfile_path); + out: + if (tmpfile_path != NULL) + (void) unlink (tmpfile_path); + unlinkat (rootfs_dfd, rpmostree_dracut_wrapper_path, 0); + return ret; +} diff --git a/src/libpriv/rpmostree-kernel.h b/src/libpriv/rpmostree-kernel.h new file mode 100644 index 00000000..b7207add --- /dev/null +++ b/src/libpriv/rpmostree-kernel.h @@ -0,0 +1,31 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2013,2014,2017 Colin Walters + * + * 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. + */ + +#pragma once + +#include + +gboolean +rpmostree_run_dracut (int rootfs_dfd, + char **argv, + int *out_initramfs_tmpfd, + char **out_initramfs_tmppath, + GCancellable *cancellable, + GError **error); diff --git a/src/libpriv/rpmostree-postprocess.c b/src/libpriv/rpmostree-postprocess.c index 16adb5f7..d6d2e240 100644 --- a/src/libpriv/rpmostree-postprocess.c +++ b/src/libpriv/rpmostree-postprocess.c @@ -38,6 +38,7 @@ #include #include "rpmostree-postprocess.h" +#include "rpmostree-kernel.h" #include "rpmostree-bwrap.h" #include "rpmostree-passwd-util.h" #include "rpmostree-rpm-util.h" @@ -50,19 +51,17 @@ typedef enum { RPMOSTREE_POSTPROCESS_BOOT_LOCATION_NEW } RpmOstreePostprocessBootLocation; +/* This bwrap case is for treecompose which isn't isn't yet operating on + * hardlinks, so we just bind mount things mutably. + */ static gboolean -run_sync_in_root_at (int rootfs_fd, - const char *binpath, - char **child_argv, - GSpawnChildSetupFunc setup_func, - gpointer data, - GError **error) +run_bwrap_mutably (int rootfs_fd, + const char *binpath, + char **child_argv, + GError **error) { g_autoptr(RpmOstreeBwrap) bwrap = NULL; - /* Bind all of the primary toplevel dirs; unlike the script case, treecompose - * isn't yet operating on hardlinks, so we can just bind mount things mutably. - */ bwrap = rpmostree_bwrap_new (rootfs_fd, RPMOSTREE_BWRAP_MUTATE_FREELY, error, "--bind", "var", "/var", "--bind", "etc", "/etc", @@ -83,9 +82,6 @@ run_sync_in_root_at (int rootfs_fd, } } - if (setup_func) - rpmostree_bwrap_set_child_setup (bwrap, setup_func, data); - if (!rpmostree_bwrap_run (bwrap, error)) return FALSE; @@ -255,88 +251,6 @@ find_ensure_one_subdirectory (int rootfs_dfd, return TRUE; } -static void -dracut_child_setup (gpointer data) -{ - int fd = GPOINTER_TO_INT (data); - - /* Move the tempfile fd to 3 (and without the cloexec flag) */ - if (dup2 (fd, 3) < 0) - err (1, "dup2"); -} - -static gboolean -run_dracut (int rootfs_dfd, - char **argv, - int *out_initramfs_tmpfd, - char **out_initramfs_tmppath, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - /* Shell wrapper around dracut to write to the O_TMPFILE fd; - * at some point in the future we should add --fd X instead of -f - * to dracut. - */ - static const char rpmostree_dracut_wrapper_path[] = "usr/bin/rpmostree-dracut-wrapper"; - /* This also hardcodes a few arguments */ - static const char rpmostree_dracut_wrapper[] = - "#!/usr/bin/bash\n" - "set -euo pipefail\n" - "extra_argv=; if (dracut --help; true) | grep -q -e --reproducible; then extra_argv=\"--reproducible --gzip\"; fi\n" - "dracut $extra_argv -v --add ostree --tmpdir=/tmp -f /tmp/initramfs.img \"$@\"\n" - "cat /tmp/initramfs.img >/proc/self/fd/3\n"; - g_autoptr(GPtrArray) child_argv = g_ptr_array_new (); - glnx_fd_close int tmp_fd = -1; - g_autofree char *tmpfile_path = NULL; - - /* First tempfile is just our shell script */ - if (!glnx_open_tmpfile_linkable_at (rootfs_dfd, "usr/bin", - O_RDWR | O_CLOEXEC, - &tmp_fd, &tmpfile_path, - error)) - goto out; - if (glnx_loop_write (tmp_fd, rpmostree_dracut_wrapper, sizeof (rpmostree_dracut_wrapper)) < 0 - || fchmod (tmp_fd, 0755) < 0) - { - glnx_set_error_from_errno (error); - goto out; - } - - if (!glnx_link_tmpfile_at (rootfs_dfd, GLNX_LINK_TMPFILE_NOREPLACE, - tmp_fd, tmpfile_path, rootfs_dfd, rpmostree_dracut_wrapper_path, - error)) - goto out; - /* We need to close the writable FD now to be able to exec it */ - close (tmp_fd); tmp_fd = -1; - - /* Second tempfile is the initramfs contents */ - if (!glnx_open_tmpfile_linkable_at (rootfs_dfd, "tmp", - O_WRONLY | O_CLOEXEC, - &tmp_fd, &tmpfile_path, - error)) - goto out; - - /* Set up argv and run */ - g_ptr_array_add (child_argv, (char*)glnx_basename (rpmostree_dracut_wrapper_path)); - for (char **iter = argv; iter && *iter; iter++) - g_ptr_array_add (child_argv, *iter); - g_ptr_array_add (child_argv, NULL); - if (!run_sync_in_root_at (rootfs_dfd, (char*)child_argv->pdata[0], (char**)child_argv->pdata, - dracut_child_setup, GINT_TO_POINTER (tmp_fd), - error)) - goto out; - - ret = TRUE; - *out_initramfs_tmpfd = tmp_fd; tmp_fd = -1; - *out_initramfs_tmppath = g_steal_pointer (&tmpfile_path); - out: - if (tmpfile_path != NULL) - (void) unlink (tmpfile_path); - unlinkat (rootfs_dfd, rpmostree_dracut_wrapper_path, 0); - return ret; -} - static gboolean do_kernel_prep (int rootfs_dfd, JsonObject *treefile, @@ -408,8 +322,7 @@ do_kernel_prep (int rootfs_dfd, { char *child_argv[] = { "depmod", (char*)kver, NULL }; - if (!run_sync_in_root_at (rootfs_dfd, "depmod", child_argv, - NULL, NULL, error)) + if (!run_bwrap_mutably (rootfs_dfd, "depmod", child_argv, error)) goto out; } @@ -445,9 +358,9 @@ do_kernel_prep (int rootfs_dfd, } g_ptr_array_add (dracut_argv, NULL); - if (!run_dracut (rootfs_dfd, (char**)dracut_argv->pdata, - &initramfs_tmp_fd, &initramfs_tmp_path, - cancellable, error)) + if (!rpmostree_run_dracut (rootfs_dfd, (char**)dracut_argv->pdata, + &initramfs_tmp_fd, &initramfs_tmp_path, + cancellable, error)) goto out; } @@ -1839,8 +1752,7 @@ rpmostree_treefile_postprocessing (int rootfs_fd, { char *child_argv[] = { binpath, NULL }; - if (!run_sync_in_root_at (rootfs_fd, binpath, child_argv, - NULL, NULL, error)) + if (!run_bwrap_mutably (rootfs_fd, binpath, child_argv, error)) { g_prefix_error (error, "While executing postprocessing script '%s': ", bn); goto out;