core: Initial implementation of %posttrans using bwrap+rofiles-fuse
In order to make many things work, we need to run scripts. Short version: For now, we: - Run `%posttrans` - Treat most `%post` as the same as `%posttrans` - Ignore `%preun` and such since we never uninstall Most importantly though, we start to build up an "override" list for script handling. Currently it's just a blacklist of scripts we don't need. Significant work here would be needed to run Lua scripts, so far I've been able to just skip them. Closes: #338 Approved by: jlebon
This commit is contained in:
parent
4738c6eb60
commit
f35f5cf468
@ -30,6 +30,8 @@ librpmostreepriv_la_SOURCES = \
|
||||
src/libpriv/rpmostree-refts.c \
|
||||
src/libpriv/rpmostree-core.c \
|
||||
src/libpriv/rpmostree-core.h \
|
||||
src/libpriv/rpmostree-scripts.c \
|
||||
src/libpriv/rpmostree-scripts.h \
|
||||
src/libpriv/rpmostree-refsack.h \
|
||||
src/libpriv/rpmostree-refsack.c \
|
||||
src/libpriv/rpmostree-cleanup.h \
|
||||
@ -57,3 +59,17 @@ librpmostreepriv_la_LIBADD = \
|
||||
libglnx.la \
|
||||
$(CAP_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
gperf_gperf_sources = src/libpriv/rpmostree-script-gperf.gperf
|
||||
BUILT_SOURCES += $(gperf_gperf_sources:-gperf.gperf=-gperf.c)
|
||||
CLEANFILES += $(gperf_gperf_sources:-gperf.gperf=-gperf.c)
|
||||
|
||||
nodist_librpmostreepriv_la_SOURCES = src/libpriv/rpmostree-script-gperf.c
|
||||
|
||||
AM_V_GPERF = $(AM_V_GPERF_$(V))
|
||||
AM_V_GPERF_ = $(AM_V_GPERF_$(AM_DEFAULT_VERBOSITY))
|
||||
AM_V_GPERF_0 = @echo " GPERF " $@;
|
||||
|
||||
src/%.c: src/%.gperf Makefile
|
||||
$(AM_V_at)$(MKDIR_P) $(dir $@)
|
||||
$(AM_V_GPERF)$(GPERF) < $< > $@.tmp && mv $@.tmp $@
|
||||
|
@ -63,6 +63,7 @@ AC_SEARCH_LIBS([rpmsqSetInterruptSafety], [rpmio],
|
||||
PKG_CHECK_MODULES(PKGDEP_GIO_UNIX, [gio-unix-2.0])
|
||||
PKG_CHECK_MODULES(PKGDEP_RPMOSTREE, [gio-unix-2.0 >= 2.40.0 json-glib-1.0
|
||||
ostree-1 >= 2015.1 libgsystem >= 2015.1
|
||||
libsystemd
|
||||
rpm libhif librepo
|
||||
libarchive])
|
||||
save_LIBS=$LIBS
|
||||
@ -74,6 +75,11 @@ AC_PATH_PROG([XSLTPROC], [xsltproc])
|
||||
|
||||
GLIB_TESTS
|
||||
|
||||
AC_CHECK_TOOL(GPERF, gperf)
|
||||
AS_IF([test -z "$GPERF"],
|
||||
AC_MSG_ERROR([*** gperf not found])
|
||||
)
|
||||
|
||||
m4_ifdef([GOBJECT_INTROSPECTION_CHECK], [
|
||||
GOBJECT_INTROSPECTION_CHECK([1.34.0])
|
||||
])
|
||||
|
@ -320,7 +320,7 @@ rpmostree_container_builtin_assemble (int argc,
|
||||
goto out;
|
||||
|
||||
if (!rpmostree_context_assemble_commit (rocctx->ctx, tmprootfs_dfd, NULL,
|
||||
NULL, TRUE, &commit, cancellable, error))
|
||||
NULL, FALSE, &commit, cancellable, error))
|
||||
goto out;
|
||||
|
||||
glnx_shutil_rm_rf_at (rocctx->userroot_dfd, tmprootfs, cancellable, NULL);
|
||||
|
@ -30,13 +30,22 @@
|
||||
static char *opt_osname;
|
||||
static gboolean opt_reboot;
|
||||
static gboolean opt_dry_run;
|
||||
/* Turn off the noscripts stuff for now, since we aren't persisting
|
||||
* it, and I hope we can mostly get away with not needing it.
|
||||
*/
|
||||
#if 0
|
||||
static gboolean opt_no_scripts;
|
||||
static char **opt_ignore_script;
|
||||
#endif
|
||||
|
||||
static GOptionEntry option_entries[] = {
|
||||
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Operate on provided OSNAME", "OSNAME" },
|
||||
{ "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Initiate a reboot after upgrade is prepared", NULL },
|
||||
{ "dry-run", 'n', 0, G_OPTION_ARG_NONE, &opt_dry_run, "Exit after printing the transaction", NULL },
|
||||
#if 0
|
||||
{ "noscripts", 0, 0, G_OPTION_ARG_NONE, &opt_no_scripts, "Do not run scripts", NULL },
|
||||
{ "ignore-script", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_ignore_script, "Ignore a script for RPM", NULL },
|
||||
#endif
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -47,8 +56,12 @@ get_args_variant (void)
|
||||
g_variant_dict_init (&dict, NULL);
|
||||
g_variant_dict_insert (&dict, "reboot", "b", opt_reboot);
|
||||
g_variant_dict_insert (&dict, "dry-run", "b", opt_dry_run);
|
||||
#if 0
|
||||
if (opt_no_scripts)
|
||||
g_variant_dict_insert (&dict, "noscripts", "b", TRUE);
|
||||
if (opt_ignore_script)
|
||||
g_variant_dict_insert (&dict, "ignore-scripts", "^as", opt_ignore_script);
|
||||
#endif
|
||||
return g_variant_dict_end (&dict);
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,7 @@ struct RpmOstreeSysrootUpgrader {
|
||||
GKeyFile *origin;
|
||||
char *origin_refspec;
|
||||
char **requested_packages;
|
||||
GHashTable *ignore_scripts;
|
||||
GHashTable *packages_to_add;
|
||||
GHashTable *packages_to_delete;
|
||||
char *override_csum;
|
||||
@ -460,6 +461,14 @@ rpmostree_sysroot_upgrader_set_origin_override (RpmOstreeSysrootUpgrader *self,
|
||||
self->override_csum = g_strdup (override_commit);
|
||||
}
|
||||
|
||||
void
|
||||
rpmostree_sysroot_upgrader_set_ignore_scripts (RpmOstreeSysrootUpgrader *self,
|
||||
GHashTable* ignore_scripts)
|
||||
{
|
||||
g_clear_pointer (&self->ignore_scripts, g_hash_table_unref);
|
||||
self->ignore_scripts = g_hash_table_ref (ignore_scripts);
|
||||
}
|
||||
|
||||
const char *
|
||||
rpmostree_sysroot_upgrader_get_refspec (RpmOstreeSysrootUpgrader *self)
|
||||
{
|
||||
@ -1116,6 +1125,9 @@ overlay_final_pkgset (RpmOstreeSysrootUpgrader *self,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (self->ignore_scripts)
|
||||
rpmostree_context_set_ignore_scripts (ctx, self->ignore_scripts);
|
||||
|
||||
if (!get_pkgcache_repo (repo, &pkgcache_repo, cancellable, error))
|
||||
goto out;
|
||||
|
||||
|
@ -80,6 +80,8 @@ gboolean rpmostree_sysroot_upgrader_set_origin_rebase (RpmOstreeSysrootUpgrader
|
||||
void rpmostree_sysroot_upgrader_set_origin_override (RpmOstreeSysrootUpgrader *self,
|
||||
const char *override_commit);
|
||||
|
||||
void rpmostree_sysroot_upgrader_set_ignore_scripts (RpmOstreeSysrootUpgrader *self,
|
||||
GHashTable* ignore_scripts);
|
||||
gboolean
|
||||
rpmostree_sysroot_upgrader_add_packages (RpmOstreeSysrootUpgrader *self,
|
||||
char **new_packages,
|
||||
|
@ -715,36 +715,6 @@ out:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static RpmOstreeTransactionPkgFlags
|
||||
pkg_opts_to_flags (GVariant *options)
|
||||
{
|
||||
gboolean v;
|
||||
RpmOstreeTransactionPkgFlags flags = 0;
|
||||
GVariantDict dict;
|
||||
|
||||
g_variant_dict_init (&dict, options);
|
||||
|
||||
v = FALSE;
|
||||
/* XXX Fail if option type is wrong? */
|
||||
g_variant_dict_lookup (&dict, "reboot", "b", &v);
|
||||
if (v)
|
||||
flags |= RPMOSTREE_TRANSACTION_PKG_FLAG_REBOOT;
|
||||
|
||||
v = FALSE;
|
||||
g_variant_dict_lookup (&dict, "dry-run", "b", &v);
|
||||
if (v)
|
||||
flags |= RPMOSTREE_TRANSACTION_PKG_FLAG_DRY_RUN;
|
||||
|
||||
v = FALSE;
|
||||
g_variant_dict_lookup (&dict, "noscripts", "b", &v);
|
||||
if (v)
|
||||
flags |= RPMOSTREE_TRANSACTION_PKG_FLAG_NOSCRIPTS;
|
||||
|
||||
g_variant_dict_clear (&dict);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
os_handle_pkg_change (RPMOSTreeOS *interface,
|
||||
GDBusMethodInvocation *invocation,
|
||||
@ -758,6 +728,10 @@ os_handle_pkg_change (RPMOSTreeOS *interface,
|
||||
glnx_unref_object GCancellable *cancellable = NULL;
|
||||
const char *osname;
|
||||
GError *local_error = NULL;
|
||||
gboolean v;
|
||||
GVariantDict dict;
|
||||
RpmOstreeTransactionPkgFlags flags = 0;
|
||||
const char *const *ignore_scripts;
|
||||
|
||||
/* If a compatible transaction is in progress, share its bus address. */
|
||||
transaction = rpmostreed_transaction_monitor_ref_active_transaction (self->transaction_monitor);
|
||||
@ -780,14 +754,37 @@ os_handle_pkg_change (RPMOSTreeOS *interface,
|
||||
|
||||
osname = rpmostree_os_get_name (interface);
|
||||
|
||||
g_variant_dict_init (&dict, arg_options);
|
||||
v = FALSE;
|
||||
/* XXX Fail if option type is wrong? */
|
||||
g_variant_dict_lookup (&dict, "reboot", "b", &v);
|
||||
if (v)
|
||||
flags |= RPMOSTREE_TRANSACTION_PKG_FLAG_REBOOT;
|
||||
|
||||
v = FALSE;
|
||||
g_variant_dict_lookup (&dict, "dry-run", "b", &v);
|
||||
if (v)
|
||||
flags |= RPMOSTREE_TRANSACTION_PKG_FLAG_DRY_RUN;
|
||||
|
||||
v = FALSE;
|
||||
g_variant_dict_lookup (&dict, "noscripts", "b", &v);
|
||||
if (v)
|
||||
flags |= RPMOSTREE_TRANSACTION_PKG_FLAG_NOSCRIPTS;
|
||||
|
||||
ignore_scripts = NULL;
|
||||
g_variant_dict_lookup (&dict, "ignore-scripts", "^a&s", (char***)&ignore_scripts);
|
||||
|
||||
transaction = rpmostreed_transaction_new_pkg_change (invocation,
|
||||
ot_sysroot,
|
||||
osname,
|
||||
arg_packages_added,
|
||||
arg_packages_removed,
|
||||
pkg_opts_to_flags (arg_options),
|
||||
ignore_scripts,
|
||||
flags,
|
||||
cancellable,
|
||||
&local_error);
|
||||
g_variant_dict_clear (&dict);
|
||||
|
||||
|
||||
if (transaction == NULL)
|
||||
goto out;
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "rpmostreed-utils.h"
|
||||
#include "rpmostree-postprocess.h"
|
||||
#include "rpmostree-rpm-util.h"
|
||||
#include "rpmostree-scripts.h"
|
||||
#include "rpmostree-core.h"
|
||||
|
||||
typedef struct {
|
||||
@ -42,6 +43,7 @@ typedef struct {
|
||||
char *osname;
|
||||
char **packages_added;
|
||||
char **packages_removed;
|
||||
GHashTable *ignore_scripts;
|
||||
RpmOstreeTransactionPkgFlags flags;
|
||||
} PkgChangeTransaction;
|
||||
|
||||
@ -62,6 +64,7 @@ pkg_change_transaction_finalize (GObject *object)
|
||||
g_free (self->osname);
|
||||
g_strfreev (self->packages_added);
|
||||
g_strfreev (self->packages_removed);
|
||||
g_clear_pointer (&self->ignore_scripts, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (pkg_change_transaction_parent_class)->finalize (object);
|
||||
}
|
||||
@ -95,6 +98,9 @@ pkg_change_transaction_execute (RpmostreedTransaction *transaction,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (self->ignore_scripts)
|
||||
rpmostree_sysroot_upgrader_set_ignore_scripts (upgrader, self->ignore_scripts);
|
||||
|
||||
if (self->packages_removed)
|
||||
{
|
||||
if (!rpmostree_sysroot_upgrader_delete_packages (upgrader, self->packages_removed,
|
||||
@ -150,11 +156,12 @@ rpmostreed_transaction_new_pkg_change (GDBusMethodInvocation *invocation,
|
||||
const char *osname,
|
||||
const char * const *packages_added,
|
||||
const char * const *packages_removed,
|
||||
const char * const *ignore_scripts,
|
||||
RpmOstreeTransactionPkgFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
PkgChangeTransaction *self;
|
||||
glnx_unref_object PkgChangeTransaction *self = NULL;
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
|
||||
g_return_val_if_fail (OSTREE_IS_SYSROOT (sysroot), NULL);
|
||||
@ -172,8 +179,10 @@ rpmostreed_transaction_new_pkg_change (GDBusMethodInvocation *invocation,
|
||||
self->osname = g_strdup (osname);
|
||||
self->packages_added = strdupv_canonicalize (packages_added);
|
||||
self->packages_removed = strdupv_canonicalize (packages_removed);
|
||||
if (!rpmostree_script_ignore_hash_from_strv (ignore_scripts, &self->ignore_scripts, error))
|
||||
return NULL;
|
||||
self->flags = flags;
|
||||
}
|
||||
|
||||
return (RpmostreedTransaction *) self;
|
||||
return (RpmostreedTransaction *) g_steal_pointer (&self);
|
||||
}
|
||||
|
@ -85,6 +85,7 @@ RpmostreedTransaction *
|
||||
const char *osname,
|
||||
const char *const *packages_added,
|
||||
const char *const *packages_removed,
|
||||
const char *const *ignore_scripts,
|
||||
RpmOstreeTransactionPkgFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "rpmostree-core.h"
|
||||
#include "rpmostree-postprocess.h"
|
||||
#include "rpmostree-rpm-util.h"
|
||||
#include "rpmostree-scripts.h"
|
||||
#include "rpmostree-unpacker.h"
|
||||
#include "rpmostree-output.h"
|
||||
|
||||
@ -168,6 +169,9 @@ rpmostree_treespec_new_from_keyfile (GKeyFile *keyfile,
|
||||
if (!add_canonicalized_string_array (&builder, "instlangs", "instlangs-all", keyfile, error))
|
||||
return NULL;
|
||||
|
||||
if (!add_canonicalized_string_array (&builder, "ignore-scripts", "", keyfile, error))
|
||||
return NULL;
|
||||
|
||||
{ gboolean documentation = TRUE;
|
||||
g_autofree char *value = g_key_file_get_value (keyfile, "tree", "documentation", NULL);
|
||||
|
||||
@ -274,6 +278,7 @@ struct _RpmOstreeContext {
|
||||
|
||||
RpmOstreeTreespec *spec;
|
||||
HifContext *hifctx;
|
||||
GHashTable *ignore_scripts;
|
||||
OstreeRepo *ostreerepo;
|
||||
gboolean unprivileged;
|
||||
char *dummy_instroot_path;
|
||||
@ -447,6 +452,15 @@ rpmostree_context_set_sepolicy (RpmOstreeContext *self,
|
||||
g_set_object (&self->sepolicy, sepolicy);
|
||||
}
|
||||
|
||||
void
|
||||
rpmostree_context_set_ignore_scripts (RpmOstreeContext *self,
|
||||
GHashTable *ignore_scripts)
|
||||
{
|
||||
g_clear_pointer (&self->ignore_scripts, g_hash_table_unref);
|
||||
if (ignore_scripts)
|
||||
self->ignore_scripts = g_hash_table_ref (ignore_scripts);
|
||||
}
|
||||
|
||||
HifContext *
|
||||
rpmostree_context_get_hif (RpmOstreeContext *self)
|
||||
{
|
||||
@ -615,6 +629,17 @@ rpmostree_context_setup (RpmOstreeContext *self,
|
||||
HIF_TRANSACTION_FLAG_NODOCS);
|
||||
}
|
||||
|
||||
{ const char *const *ignore_scripts = NULL;
|
||||
if (g_variant_dict_lookup (self->spec->dict, "ignore-scripts", "^a&s", &ignore_scripts))
|
||||
{
|
||||
g_autoptr(GHashTable) ignore_hash = NULL;
|
||||
|
||||
if (!rpmostree_script_ignore_hash_from_strv (ignore_scripts, &ignore_hash, error))
|
||||
goto out;
|
||||
rpmostree_context_set_ignore_scripts (self, ignore_hash);
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
@ -1897,102 +1922,48 @@ ts_callback (const void * h,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *desc;
|
||||
rpmsenseFlags sense;
|
||||
rpmTagVal tag;
|
||||
rpmTagVal progtag;
|
||||
rpmTagVal flagtag;
|
||||
} KnownRpmScriptKind;
|
||||
|
||||
static const KnownRpmScriptKind known_scripts[] = {
|
||||
{ "%prein", 0,
|
||||
RPMTAG_PREIN, RPMTAG_PREINPROG, RPMTAG_PREINFLAGS },
|
||||
{ "%preun", 0,
|
||||
RPMTAG_PREUN, RPMTAG_PREUNPROG, RPMTAG_PREUNFLAGS },
|
||||
{ "%post", 0,
|
||||
RPMTAG_POSTIN, RPMTAG_POSTINPROG, RPMTAG_POSTINFLAGS },
|
||||
{ "%postun", 0,
|
||||
RPMTAG_POSTUN, RPMTAG_POSTUNPROG, RPMTAG_POSTUNFLAGS },
|
||||
{ "%pretrans", 0,
|
||||
RPMTAG_PRETRANS, RPMTAG_PRETRANSPROG, RPMTAG_PRETRANSFLAGS },
|
||||
{ "%posttrans", 0,
|
||||
RPMTAG_POSTTRANS, RPMTAG_POSTTRANSPROG, RPMTAG_POSTTRANSFLAGS },
|
||||
{ "%triggerprein", RPMSENSE_TRIGGERPREIN,
|
||||
RPMTAG_TRIGGERPREIN, 0, 0 },
|
||||
{ "%triggerun", RPMSENSE_TRIGGERUN,
|
||||
RPMTAG_TRIGGERUN, 0, 0 },
|
||||
{ "%triggerin", RPMSENSE_TRIGGERIN,
|
||||
RPMTAG_TRIGGERIN, 0, 0 },
|
||||
{ "%triggerpostun", RPMSENSE_TRIGGERPOSTUN,
|
||||
RPMTAG_TRIGGERPOSTUN, 0, 0 },
|
||||
{ "%verify", 0,
|
||||
RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG, RPMTAG_VERIFYSCRIPTFLAGS},
|
||||
};
|
||||
|
||||
/*
|
||||
* We aren't yet running %posts, so let's not lie and say we support
|
||||
* it.
|
||||
*/
|
||||
#if 0
|
||||
static gboolean
|
||||
check_package_is_post_posts (Header hdr,
|
||||
const char *name,
|
||||
GError **error)
|
||||
static Header
|
||||
get_header_for_package (int tmp_metadata_dfd,
|
||||
HifPackage *pkg,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (known_scripts); i++)
|
||||
{
|
||||
rpmTagVal tagval = known_scripts[i].tag;
|
||||
rpmTagVal progtagval = known_scripts[i].progtag;
|
||||
|
||||
if (headerIsEntry (hdr, tagval) || headerIsEntry (hdr, progtagval))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Package '%s' has (currently) unsupported script of type '%s'",
|
||||
name, known_scripts[i].desc);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
add_to_transaction (rpmts ts,
|
||||
HifPackage *pkg,
|
||||
int tmp_metadata_dfd,
|
||||
gboolean noscripts,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int r;
|
||||
Header hdr = NULL;
|
||||
glnx_fd_close int metadata_fd = -1;
|
||||
|
||||
if ((metadata_fd = openat (tmp_metadata_dfd, hif_package_get_nevra (pkg), O_RDONLY | O_CLOEXEC)) < 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!rpmostree_unpacker_read_metainfo (metadata_fd, &hdr, NULL, NULL, error))
|
||||
return NULL;
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
add_to_transaction (rpmts ts,
|
||||
HifPackage *pkg,
|
||||
int tmp_metadata_dfd,
|
||||
gboolean noscripts,
|
||||
GHashTable *ignore_scripts,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
Header hdr = NULL;
|
||||
int r;
|
||||
|
||||
hdr = get_header_for_package (tmp_metadata_dfd, pkg, error);
|
||||
if (!hdr)
|
||||
goto out;
|
||||
|
||||
/* TODO uncomment once upgrade understands this or we implement post
|
||||
handling better */
|
||||
#if 0
|
||||
if (!noscripts)
|
||||
{
|
||||
if (!check_package_is_post_posts (hdr, hif_package_get_nevra (pkg), error))
|
||||
if (!rpmostree_script_txn_validate (pkg, hdr, ignore_scripts, cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
r = rpmtsAddInstallElement (ts, hdr, (char*)hif_package_get_nevra (pkg), TRUE, NULL);
|
||||
if (r != 0)
|
||||
@ -2012,6 +1983,32 @@ add_to_transaction (rpmts ts,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
run_posttrans_sync (int tmp_metadata_dfd,
|
||||
int rootfs_dfd,
|
||||
HifPackage *pkg,
|
||||
GHashTable *ignore_scripts,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
Header hdr;
|
||||
|
||||
hdr = get_header_for_package (tmp_metadata_dfd, pkg, error);
|
||||
if (!hdr)
|
||||
goto out;
|
||||
|
||||
if (!rpmostree_posttrans_run_sync (pkg, hdr, ignore_scripts, rootfs_dfd,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (hdr)
|
||||
headerFree (hdr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* FIXME: This is a copy of ot_admin_checksum_version */
|
||||
static char *
|
||||
checksum_version (GVariant *checksum)
|
||||
@ -2131,7 +2128,9 @@ rpmostree_context_assemble_commit (RpmOstreeContext *self,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!add_to_transaction (ordering_ts, pkg, tmp_metadata_dfd, noscripts, error))
|
||||
if (!add_to_transaction (ordering_ts, pkg, tmp_metadata_dfd, noscripts,
|
||||
self->ignore_scripts,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -2215,6 +2214,24 @@ rpmostree_context_assemble_commit (RpmOstreeContext *self,
|
||||
|
||||
rpmostree_output_task_end ("done");
|
||||
|
||||
if (!rpmostree_rootfs_prepare_links (tmprootfs_dfd, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!noscripts)
|
||||
{
|
||||
for (i = 0; i < n_rpmts_elements; i++)
|
||||
{
|
||||
rpmte te = rpmtsElement (ordering_ts, i);
|
||||
const char *tekey = rpmteKey (te);
|
||||
HifPackage *pkg = g_hash_table_lookup (nevra_to_pkg, tekey);
|
||||
|
||||
if (!run_posttrans_sync (tmp_metadata_dfd, tmprootfs_dfd, pkg,
|
||||
self->ignore_scripts,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
g_clear_pointer (&ordering_ts, rpmtsFree);
|
||||
|
||||
rpmostree_output_task_begin ("Writing rpmdb");
|
||||
@ -2255,7 +2272,9 @@ rpmostree_context_assemble_commit (RpmOstreeContext *self,
|
||||
{
|
||||
HifPackage *pkg = k;
|
||||
|
||||
if (!add_to_transaction (rpmdb_ts, pkg, tmp_metadata_dfd, noscripts, error))
|
||||
/* Set noscripts since we already validated them above */
|
||||
if (!add_to_transaction (rpmdb_ts, pkg, tmp_metadata_dfd, TRUE, NULL,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,8 @@ void rpmostree_context_set_repo (RpmOstreeContext *self,
|
||||
OstreeRepo *repo);
|
||||
void rpmostree_context_set_sepolicy (RpmOstreeContext *self,
|
||||
OstreeSePolicy *sepolicy);
|
||||
void rpmostree_context_set_ignore_scripts (RpmOstreeContext *self,
|
||||
GHashTable *ignore_scripts);
|
||||
|
||||
void rpmostree_hif_add_checksum_goal (GChecksum *checksum, HyGoal goal);
|
||||
char *rpmostree_context_get_state_sha512 (RpmOstreeContext *self);
|
||||
|
@ -866,6 +866,8 @@ create_rootfs_from_yumroot_content (GFile *targetroot,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!rpmostree_rootfs_prepare_links (target_root_dfd, cancellable, error))
|
||||
goto out;
|
||||
if (!rpmostree_rootfs_postprocess_common (target_root_dfd, cancellable, error))
|
||||
goto out;
|
||||
|
||||
@ -1104,6 +1106,87 @@ rename_if_exists (int dfd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
rpmostree_rootfs_symlink_emptydir_at (int rootfs_fd,
|
||||
const char *dest,
|
||||
const char *src,
|
||||
GError **error)
|
||||
{
|
||||
const char *parent = dirname (strdupa (src));
|
||||
struct stat stbuf;
|
||||
gboolean make_symlink = TRUE;
|
||||
|
||||
/* For maximum compatibility, create parent directories too. This
|
||||
* is necessary when we're doing layering on top of a base commit,
|
||||
* and the /var will be empty. We should probably consider running
|
||||
* systemd-tmpfiles to setup the temporary /var.
|
||||
*/
|
||||
if (parent && strcmp (parent, ".") != 0)
|
||||
{
|
||||
if (!glnx_shutil_mkdir_p_at (rootfs_fd, parent, 0755, NULL, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (fstatat (rootfs_fd, src, &stbuf, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (S_ISLNK (stbuf.st_mode))
|
||||
make_symlink = FALSE;
|
||||
else if (S_ISDIR (stbuf.st_mode))
|
||||
{
|
||||
if (unlinkat (rootfs_fd, src, AT_REMOVEDIR) < 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "Removing %s", src);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (make_symlink)
|
||||
{
|
||||
if (symlinkat (dest, rootfs_fd, src) < 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "Symlinking %s", src);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* rpmostree_rootfs_prepare_links:
|
||||
*
|
||||
* Walk over the root filesystem and perform some core conversions
|
||||
* from RPM conventions to OSTree conventions. For example:
|
||||
*
|
||||
* - Symlink /usr/local -> /var/usrlocal
|
||||
* - Symlink /var/lib/alternatives -> /usr/lib/alternatives
|
||||
*/
|
||||
gboolean
|
||||
rpmostree_rootfs_prepare_links (int rootfs_fd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
if (!glnx_shutil_rm_rf_at (rootfs_fd, "usr/local", cancellable, error))
|
||||
return FALSE;
|
||||
if (!rpmostree_rootfs_symlink_emptydir_at (rootfs_fd, "../var/usrlocal", "usr/local", error))
|
||||
return FALSE;
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (rootfs_fd, "usr/lib/alternatives", 0755, cancellable, error))
|
||||
return FALSE;
|
||||
if (!rpmostree_rootfs_symlink_emptydir_at (rootfs_fd, "../../usr/lib/alternatives", "var/lib/alternatives", error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* rpmostree_rootfs_postprocess_common:
|
||||
*
|
||||
@ -1111,8 +1194,7 @@ rename_if_exists (int dfd,
|
||||
* from RPM conventions to OSTree conventions. For example:
|
||||
*
|
||||
* - Move /etc to /usr/etc
|
||||
* - Symlink /usr/local -> /var/usrlocal
|
||||
* - Clean up RPM database leftovers and lock files
|
||||
* - Clean up RPM db leftovers
|
||||
*/
|
||||
gboolean
|
||||
rpmostree_rootfs_postprocess_common (int rootfs_fd,
|
||||
@ -1121,17 +1203,7 @@ rpmostree_rootfs_postprocess_common (int rootfs_fd,
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
|
||||
if (!glnx_shutil_rm_rf_at (rootfs_fd, "usr/local", cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (symlinkat ("../var/usrlocal", rootfs_fd, "usr/local") < 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
g_prefix_error (error, "Creating usr/local symlink: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
if (!rename_if_exists (rootfs_fd, "etc", "usr/etc", error))
|
||||
goto out;
|
||||
|
||||
|
@ -32,6 +32,16 @@ rpmostree_treefile_postprocessing (GFile *rootfs,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_rootfs_symlink_emptydir_at (int rootfs_fd,
|
||||
const char *dest,
|
||||
const char *src,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_rootfs_prepare_links (int rootfs_fd,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
gboolean
|
||||
rpmostree_rootfs_postprocess_common (int rootfs_fd,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
27
src/libpriv/rpmostree-script-gperf.gperf
Normal file
27
src/libpriv/rpmostree-script-gperf.gperf
Normal file
@ -0,0 +1,27 @@
|
||||
%{
|
||||
#include "config.h"
|
||||
#include "rpmostree-scripts.h"
|
||||
%}
|
||||
struct RpmOstreePackageScriptHandler;
|
||||
%language=ANSI-C
|
||||
%define slot-name package_script
|
||||
%define hash-function-name rpmostree_script_gperf_hash
|
||||
%define lookup-function-name rpmostree_script_gperf_lookup
|
||||
%readonly-tables
|
||||
%omit-struct-type
|
||||
%struct-type
|
||||
%includes
|
||||
%%
|
||||
glibc.prein, RPMOSTREE_SCRIPT_ACTION_IGNORE
|
||||
coreutils.prein, RPMOSTREE_SCRIPT_ACTION_IGNORE /* workaround for old bug? */
|
||||
ca-certificates.prein, RPMOSTREE_SCRIPT_ACTION_IGNORE /* Looks like legacy... */
|
||||
filesystem.pretrans, RPMOSTREE_SCRIPT_ACTION_IGNORE
|
||||
libgcc.post, RPMOSTREE_SCRIPT_ACTION_IGNORE
|
||||
setup.post, RPMOSTREE_SCRIPT_ACTION_IGNORE
|
||||
pinentry.prein, RPMOSTREE_SCRIPT_ACTION_IGNORE
|
||||
fedora-release.post, RPMOSTREE_SCRIPT_ACTION_IGNORE
|
||||
fedora-release.posttrans, RPMOSTREE_SCRIPT_ACTION_IGNORE
|
||||
bash.post, RPMOSTREE_SCRIPT_ACTION_TODO_SHELL_POSTTRANS
|
||||
glibc-common.post, RPMOSTREE_SCRIPT_ACTION_TODO_SHELL_POSTTRANS
|
||||
/* Seems to be another case of legacy workaround */
|
||||
gdb.prein, RPMOSTREE_SCRIPT_ACTION_IGNORE
|
402
src/libpriv/rpmostree-scripts.c
Normal file
402
src/libpriv/rpmostree-scripts.c
Normal file
@ -0,0 +1,402 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright (C) 2016 Red Hat, Inc.
|
||||
*
|
||||
* 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 <gio/gio.h>
|
||||
#include <systemd/sd-journal.h>
|
||||
#include "rpmostree-output.h"
|
||||
#include <err.h>
|
||||
#include "libglnx.h"
|
||||
|
||||
#include "rpmostree-scripts.h"
|
||||
|
||||
typedef struct {
|
||||
const char *desc;
|
||||
rpmsenseFlags sense;
|
||||
rpmTagVal tag;
|
||||
rpmTagVal progtag;
|
||||
rpmTagVal flagtag;
|
||||
} KnownRpmScriptKind;
|
||||
|
||||
#if 0
|
||||
static const KnownRpmScriptKind ignored_scripts[] = {
|
||||
/* Ignore all of the *un variants since we never uninstall
|
||||
* anything in the RPM sense.
|
||||
*/
|
||||
{ "%preun", 0,
|
||||
RPMTAG_PREUN, RPMTAG_PREUNPROG, RPMTAG_PREUNFLAGS },
|
||||
{ "%postun", 0,
|
||||
RPMTAG_POSTUN, RPMTAG_POSTUNPROG, RPMTAG_POSTUNFLAGS },
|
||||
{ "%triggerun", RPMSENSE_TRIGGERUN,
|
||||
RPMTAG_TRIGGERUN, 0, 0 },
|
||||
{ "%triggerpostun", RPMSENSE_TRIGGERPOSTUN,
|
||||
RPMTAG_TRIGGERPOSTUN, 0, 0 },
|
||||
};
|
||||
#endif
|
||||
|
||||
static const KnownRpmScriptKind posttrans_scripts[] = {
|
||||
/* For now, we treat %post as equivalent to %posttrans */
|
||||
{ "%post", 0,
|
||||
RPMTAG_POSTIN, RPMTAG_POSTINPROG, RPMTAG_POSTINFLAGS },
|
||||
{ "%posttrans", 0,
|
||||
RPMTAG_POSTTRANS, RPMTAG_POSTTRANSPROG, RPMTAG_POSTTRANSFLAGS },
|
||||
};
|
||||
|
||||
static const KnownRpmScriptKind unsupported_scripts[] = {
|
||||
{ "%prein", 0,
|
||||
RPMTAG_PREIN, RPMTAG_PREINPROG, RPMTAG_PREINFLAGS },
|
||||
{ "%pretrans", 0,
|
||||
RPMTAG_PRETRANS, RPMTAG_PRETRANSPROG, RPMTAG_PRETRANSFLAGS },
|
||||
{ "%triggerprein", RPMSENSE_TRIGGERPREIN,
|
||||
RPMTAG_TRIGGERPREIN, 0, 0 },
|
||||
{ "%triggerin", RPMSENSE_TRIGGERIN,
|
||||
RPMTAG_TRIGGERIN, 0, 0 },
|
||||
{ "%verify", 0,
|
||||
RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG, RPMTAG_VERIFYSCRIPTFLAGS},
|
||||
};
|
||||
|
||||
static void
|
||||
child_setup_fchdir (gpointer user_data)
|
||||
{
|
||||
int fd = GPOINTER_TO_INT (user_data);
|
||||
if (fchdir (fd) < 0)
|
||||
err (1, "fchdir");
|
||||
}
|
||||
|
||||
static void
|
||||
add_const_args (GPtrArray *argv_array, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *arg;
|
||||
|
||||
va_start (args, argv_array);
|
||||
while ((arg = va_arg (args, char *)))
|
||||
g_ptr_array_add (argv_array, arg);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
static void
|
||||
fusermount_cleanup (const char *mountpoint)
|
||||
{
|
||||
g_autoptr(GError) tmp_error = NULL;
|
||||
const char *fusermount_argv[] = { "fusermount", "-u", mountpoint, NULL};
|
||||
int estatus;
|
||||
|
||||
if (!g_spawn_sync (NULL, (char**)fusermount_argv, NULL, G_SPAWN_SEARCH_PATH,
|
||||
NULL, NULL, NULL, NULL, &estatus, &tmp_error))
|
||||
{
|
||||
g_prefix_error (&tmp_error, "Executing fusermount: ");
|
||||
goto out;
|
||||
}
|
||||
if (!g_spawn_check_exit_status (estatus, &tmp_error))
|
||||
{
|
||||
g_prefix_error (&tmp_error, "Executing fusermount: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
/* We don't want a failure to unmount to be fatal, so all we do here
|
||||
* is log. Though in practice what we *really* want is for the
|
||||
* fusermount to be in the bwrap namespace, and hence tied by the
|
||||
* kernel to the lifecycle of the container. This would require
|
||||
* special casing for somehow doing FUSE mounts in bwrap. Which
|
||||
* would be hard because NO_NEW_PRIVS turns off the setuid bits for
|
||||
* fuse.
|
||||
*/
|
||||
if (tmp_error)
|
||||
sd_journal_print (LOG_WARNING, "%s", tmp_error->message);
|
||||
}
|
||||
|
||||
static RpmOstreeScriptAction
|
||||
lookup_script_action (HifPackage *package,
|
||||
GHashTable *ignored_scripts,
|
||||
const char *scriptdesc)
|
||||
{
|
||||
const char *pkg_script = glnx_strjoina (hif_package_get_name (package), ".", scriptdesc+1);
|
||||
const struct RpmOstreePackageScriptHandler *handler = rpmostree_script_gperf_lookup (pkg_script, strlen (pkg_script));
|
||||
if (ignored_scripts && g_hash_table_contains (ignored_scripts, pkg_script))
|
||||
return RPMOSTREE_SCRIPT_ACTION_IGNORE;
|
||||
if (!handler)
|
||||
return RPMOSTREE_SCRIPT_ACTION_DEFAULT;
|
||||
return handler->action;
|
||||
}
|
||||
|
||||
gboolean
|
||||
rpmostree_script_txn_validate (HifPackage *package,
|
||||
Header hdr,
|
||||
GHashTable *override_ignored_scripts,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (unsupported_scripts); i++)
|
||||
{
|
||||
const char *desc = unsupported_scripts[i].desc;
|
||||
rpmTagVal tagval = unsupported_scripts[i].tag;
|
||||
rpmTagVal progtagval = unsupported_scripts[i].progtag;
|
||||
RpmOstreeScriptAction action;
|
||||
|
||||
if (!(headerIsEntry (hdr, tagval) || headerIsEntry (hdr, progtagval)))
|
||||
continue;
|
||||
|
||||
action = lookup_script_action (package, override_ignored_scripts, desc);
|
||||
switch (action)
|
||||
{
|
||||
case RPMOSTREE_SCRIPT_ACTION_DEFAULT:
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Package '%s' has (currently) unsupported script of type '%s'",
|
||||
hif_package_get_name (package), desc);
|
||||
goto out;
|
||||
}
|
||||
case RPMOSTREE_SCRIPT_ACTION_IGNORE:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
run_script_in_bwrap_container (int rootfs_fd,
|
||||
const char *name,
|
||||
const char *scriptdesc,
|
||||
const char *script,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int i;
|
||||
const char *usr_links[] = {"lib", "lib32", "lib64", "bin", "sbin"};
|
||||
int estatus;
|
||||
char *rofiles_mnt = strdupa ("/tmp/rofiles-fuse.XXXXXX");
|
||||
const char *rofiles_argv[] = { "rofiles-fuse", "./usr", rofiles_mnt, NULL};
|
||||
const char *pkg_script = glnx_strjoina (name, ".", scriptdesc+1);
|
||||
const char *postscript_name = glnx_strjoina ("/", pkg_script);
|
||||
const char *postscript_path_container = glnx_strjoina ("/usr/", postscript_name);
|
||||
const char *postscript_path_host;
|
||||
gboolean mntpoint_created = FALSE;
|
||||
gboolean fuse_mounted = FALSE;
|
||||
g_autoptr(GPtrArray) bwrap_argv = g_ptr_array_new ();
|
||||
g_autoptr(GPtrArray) bwrap_argv_mallocd = g_ptr_array_new_with_free_func (g_free);
|
||||
GSpawnFlags bwrap_spawnflags = G_SPAWN_SEARCH_PATH;
|
||||
gboolean created_var_tmp = FALSE;
|
||||
|
||||
if (!glnx_mkdtempat (AT_FDCWD, rofiles_mnt, 0700, error))
|
||||
goto out;
|
||||
|
||||
mntpoint_created = TRUE;
|
||||
|
||||
if (!g_spawn_sync (NULL, (char**)rofiles_argv, NULL, G_SPAWN_SEARCH_PATH,
|
||||
child_setup_fchdir, GINT_TO_POINTER (rootfs_fd),
|
||||
NULL, NULL, &estatus, error))
|
||||
goto out;
|
||||
if (!g_spawn_check_exit_status (estatus, error))
|
||||
{
|
||||
g_prefix_error (error, "Executing rofiles-fuse: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
fuse_mounted = TRUE;
|
||||
|
||||
postscript_path_host = glnx_strjoina (rofiles_mnt, "/", postscript_name);
|
||||
|
||||
/* TODO - Create a pipe and send this to bwrap so it's inside the
|
||||
* tmpfs
|
||||
*/
|
||||
if (!g_file_set_contents (postscript_path_host, script, -1, error))
|
||||
{
|
||||
g_prefix_error (error, "Writing script to %s: ", postscript_path_host);
|
||||
goto out;
|
||||
}
|
||||
if (chmod (postscript_path_host, 0755) != 0)
|
||||
{
|
||||
g_prefix_error (error, "chmod %s: ", postscript_path_host);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We need to make the mount point in the case where we're doing
|
||||
* package layering, since the host `/var` tree is empty. We
|
||||
* *could* point at the real `/var`...but that seems
|
||||
* unnecessary/dangerous to me. Daemons that need to perform data
|
||||
* migrations should do them as part of their systemd units and not
|
||||
* in %post.
|
||||
*
|
||||
* Another alternative would be to make a tmpfs with the compat
|
||||
* symlinks.
|
||||
*/
|
||||
if (mkdirat (rootfs_fd, "var/tmp", 0755) < 0)
|
||||
{
|
||||
if (errno == EEXIST)
|
||||
;
|
||||
else
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
created_var_tmp = TRUE;
|
||||
|
||||
add_const_args (bwrap_argv,
|
||||
"bwrap",
|
||||
"--bind", rofiles_mnt, "/usr",
|
||||
"--dev", "/dev",
|
||||
"--proc", "/proc",
|
||||
"--dir", "/tmp",
|
||||
"--chdir", "/",
|
||||
/* Scripts can see a /var with compat links like alternatives */
|
||||
"--ro-bind", "./var", "/var",
|
||||
/* But no need to access persistent /tmp, so make it /tmp */
|
||||
"--bind", "/tmp", "/var/tmp",
|
||||
/* Allow RPM scripts to change the /etc defaults */
|
||||
"--symlink", "usr/etc", "/etc",
|
||||
"--ro-bind", "/sys/block", "/sys/block",
|
||||
"--ro-bind", "/sys/bus", "/sys/bus",
|
||||
"--ro-bind", "/sys/class", "/sys/class",
|
||||
"--ro-bind", "/sys/dev", "/sys/dev",
|
||||
"--ro-bind", "/sys/devices", "/sys/devices",
|
||||
NULL);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (usr_links); i++)
|
||||
{
|
||||
const char *subdir = usr_links[i];
|
||||
struct stat stbuf;
|
||||
char *path;
|
||||
|
||||
if (!(fstatat (rootfs_fd, subdir, &stbuf, AT_SYMLINK_NOFOLLOW) == 0 && S_ISLNK (stbuf.st_mode)))
|
||||
continue;
|
||||
|
||||
g_ptr_array_add (bwrap_argv, "--symlink");
|
||||
|
||||
path = g_strconcat ("usr/", subdir, NULL);
|
||||
g_ptr_array_add (bwrap_argv_mallocd, path);
|
||||
g_ptr_array_add (bwrap_argv, path);
|
||||
|
||||
path = g_strconcat ("/", subdir, NULL);
|
||||
g_ptr_array_add (bwrap_argv_mallocd, path);
|
||||
g_ptr_array_add (bwrap_argv, path);
|
||||
}
|
||||
|
||||
{ const char *debugscript = getenv ("RPMOSTREE_DEBUG_SCRIPT");
|
||||
if (g_strcmp0 (debugscript, pkg_script) == 0)
|
||||
{
|
||||
g_ptr_array_add (bwrap_argv, (char*)"/bin/bash");
|
||||
bwrap_spawnflags |= G_SPAWN_CHILD_INHERITS_STDIN;
|
||||
}
|
||||
else
|
||||
g_ptr_array_add (bwrap_argv, (char*)postscript_path_container);
|
||||
}
|
||||
g_ptr_array_add (bwrap_argv, NULL);
|
||||
|
||||
if (!g_spawn_sync (NULL, (char**)bwrap_argv->pdata, NULL, bwrap_spawnflags,
|
||||
child_setup_fchdir, GINT_TO_POINTER (rootfs_fd),
|
||||
NULL, NULL, &estatus, error))
|
||||
{
|
||||
g_prefix_error (error, "Executing bwrap: ");
|
||||
goto out;
|
||||
}
|
||||
if (!g_spawn_check_exit_status (estatus, error))
|
||||
{
|
||||
g_prefix_error (error, "Executing bwrap: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (fuse_mounted)
|
||||
{
|
||||
(void) unlink (postscript_path_host);
|
||||
fusermount_cleanup (rofiles_mnt);
|
||||
}
|
||||
if (mntpoint_created)
|
||||
(void) unlinkat (AT_FDCWD, rofiles_mnt, AT_REMOVEDIR);
|
||||
if (created_var_tmp)
|
||||
(void) unlinkat (rootfs_fd, "var/tmp", AT_REMOVEDIR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
rpmostree_posttrans_run_sync (HifPackage *pkg,
|
||||
Header hdr,
|
||||
GHashTable *ignore_scripts,
|
||||
int rootfs_fd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
for (guint i = 0; i < G_N_ELEMENTS (posttrans_scripts); i++)
|
||||
{
|
||||
const char *desc = posttrans_scripts[i].desc;
|
||||
rpmTagVal tagval = posttrans_scripts[i].tag;
|
||||
rpmTagVal progtagval = posttrans_scripts[i].progtag;
|
||||
const char *script;
|
||||
RpmOstreeScriptAction action;
|
||||
|
||||
if (!(headerIsEntry (hdr, tagval) || headerIsEntry (hdr, progtagval)))
|
||||
continue;
|
||||
|
||||
script = headerGetString (hdr, tagval);
|
||||
if (!script)
|
||||
continue;
|
||||
|
||||
action = lookup_script_action (pkg, ignore_scripts, desc);
|
||||
switch (action)
|
||||
{
|
||||
case RPMOSTREE_SCRIPT_ACTION_DEFAULT:
|
||||
{
|
||||
rpmostree_output_task_begin ("Running %s for %s...", desc, hif_package_get_name (pkg));
|
||||
if (!run_script_in_bwrap_container (rootfs_fd, hif_package_get_name (pkg), desc, script,
|
||||
cancellable, error))
|
||||
{
|
||||
g_prefix_error (error, "Running %s for %s: ", desc, hif_package_get_name (pkg));
|
||||
return FALSE;
|
||||
}
|
||||
rpmostree_output_task_end ("done");
|
||||
}
|
||||
case RPMOSTREE_SCRIPT_ACTION_IGNORE:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
rpmostree_script_ignore_hash_from_strv (const char *const *strv,
|
||||
GHashTable **out_hash,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GHashTable) ignore_scripts = NULL;
|
||||
if (!strv)
|
||||
{
|
||||
*out_hash = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
ignore_scripts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
for (const char *const* iter = strv; iter && *iter; iter++)
|
||||
g_hash_table_add (ignore_scripts, g_strdup (*iter));
|
||||
*out_hash = g_steal_pointer (&ignore_scripts);
|
||||
return TRUE;
|
||||
}
|
65
src/libpriv/rpmostree-scripts.h
Normal file
65
src/libpriv/rpmostree-scripts.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <ostree.h>
|
||||
#include <rpm/rpmsq.h>
|
||||
#include <rpm/rpmlib.h>
|
||||
#include <rpm/rpmlog.h>
|
||||
#include <rpm/rpmfi.h>
|
||||
#include <rpm/rpmmacro.h>
|
||||
#include <rpm/rpmts.h>
|
||||
#include <libhif/libhif.h>
|
||||
|
||||
#include "libglnx.h"
|
||||
|
||||
typedef enum {
|
||||
RPMOSTREE_SCRIPT_ACTION_DEFAULT = 0,
|
||||
RPMOSTREE_SCRIPT_ACTION_IGNORE,
|
||||
RPMOSTREE_SCRIPT_ACTION_TODO_SHELL_POSTTRANS = RPMOSTREE_SCRIPT_ACTION_IGNORE,
|
||||
} RpmOstreeScriptAction;
|
||||
|
||||
struct RpmOstreePackageScriptHandler {
|
||||
const char *package_script;
|
||||
RpmOstreeScriptAction action;
|
||||
};
|
||||
|
||||
const struct RpmOstreePackageScriptHandler* rpmostree_script_gperf_lookup(const char *key, unsigned length);
|
||||
|
||||
gboolean rpmostree_script_ignore_hash_from_strv (const char *const *strv,
|
||||
GHashTable **out_hash,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_script_txn_validate (HifPackage *package,
|
||||
Header hdr,
|
||||
GHashTable *ignore_scripts,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_posttrans_run_sync (HifPackage *pkg,
|
||||
Header hdr,
|
||||
GHashTable *ignore_scripts,
|
||||
int rootfs_fd,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
Loading…
Reference in New Issue
Block a user