2015-07-23 18:30:33 +03:00
/*
* Copyright ( C ) 2015 Red Hat , Inc .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program 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 General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include "config.h"
# include "ostree.h"
# include <libglnx.h>
2015-08-24 22:44:40 +03:00
# include "rpmostreed-transaction.h"
# include "rpmostreed-errors.h"
# include "rpmostreed-sysroot.h"
2015-07-23 18:30:33 +03:00
2015-08-24 22:44:40 +03:00
struct _RpmostreedTransactionPrivate {
2015-08-17 00:41:48 +03:00
GDBusMethodInvocation * invocation ;
2015-08-13 17:03:56 +03:00
GCancellable * cancellable ;
2015-07-23 18:30:33 +03:00
2015-08-13 17:56:06 +03:00
/* Locked for the duration of the transaction. */
OstreeSysroot * sysroot ;
2015-08-17 20:42:03 +03:00
GDBusServer * server ;
2015-08-26 19:57:02 +03:00
GHashTable * peer_connections ;
/* For emitting Finished signals to late connections. */
GVariant * finished_params ;
2015-08-17 20:42:03 +03:00
2015-07-23 18:30:33 +03:00
guint watch_id ;
} ;
enum {
2015-08-13 17:56:06 +03:00
PROP_0 ,
2015-08-26 19:57:02 +03:00
PROP_ACTIVE ,
2015-08-17 00:41:48 +03:00
PROP_INVOCATION ,
2015-08-13 17:56:06 +03:00
PROP_SYSROOT
2015-07-23 18:30:33 +03:00
} ;
enum {
2015-08-18 23:14:34 +03:00
CLOSED ,
2015-07-23 18:30:33 +03:00
LAST_SIGNAL
} ;
static guint signals [ LAST_SIGNAL ] ;
2015-08-24 22:44:40 +03:00
static void rpmostreed_transaction_initable_iface_init ( GInitableIface * iface ) ;
static void rpmostreed_transaction_dbus_iface_init ( RPMOSTreeTransactionIface * iface ) ;
2015-07-23 18:30:33 +03:00
2015-08-13 19:53:58 +03:00
/* XXX I tried using G_ADD_PRIVATE here, but was getting memory corruption
* on the 2 nd instance and valgrind was going crazy with invalid reads
* and writes . So I ' m falling back to the allegedly deprecated method
* and deferring further investigation . */
2015-08-24 22:44:40 +03:00
G_DEFINE_ABSTRACT_TYPE_WITH_CODE ( RpmostreedTransaction ,
rpmostreed_transaction ,
2015-08-13 20:17:01 +03:00
RPMOSTREE_TYPE_TRANSACTION_SKELETON ,
G_IMPLEMENT_INTERFACE ( G_TYPE_INITABLE ,
2015-08-24 22:44:40 +03:00
rpmostreed_transaction_initable_iface_init )
2015-08-13 20:17:01 +03:00
G_IMPLEMENT_INTERFACE ( RPMOSTREE_TYPE_TRANSACTION ,
2015-08-24 22:44:40 +03:00
rpmostreed_transaction_dbus_iface_init ) )
2015-07-23 18:30:33 +03:00
2015-08-13 19:53:58 +03:00
/* XXX This is lame but it's meant to keep it simple to
* transition to transaction_get_instance_private ( ) . */
2015-08-24 22:44:40 +03:00
static RpmostreedTransactionPrivate *
rpmostreed_transaction_get_private ( RpmostreedTransaction * self )
2015-08-13 19:53:58 +03:00
{
return self - > priv ;
}
2015-08-26 19:57:02 +03:00
static void
transaction_maybe_emit_closed ( RpmostreedTransaction * self )
{
RpmostreedTransactionPrivate * priv = rpmostreed_transaction_get_private ( self ) ;
if ( rpmostreed_transaction_get_active ( self ) )
return ;
if ( g_hash_table_size ( priv - > peer_connections ) > 0 )
return ;
g_signal_emit ( self , signals [ CLOSED ] , 0 ) ;
}
2015-08-18 23:14:34 +03:00
static void
transaction_connection_closed_cb ( GDBusConnection * connection ,
gboolean remote_peer_vanished ,
GError * error ,
2015-08-24 22:44:40 +03:00
RpmostreedTransaction * self )
2015-08-18 23:14:34 +03:00
{
2015-08-26 19:57:02 +03:00
RpmostreedTransactionPrivate * priv = rpmostreed_transaction_get_private ( self ) ;
2015-08-20 22:00:43 +03:00
g_debug ( " %s (%p): Client disconnected " ,
G_OBJECT_TYPE_NAME ( self ) , self ) ;
2015-08-26 19:57:02 +03:00
g_hash_table_remove ( priv - > peer_connections , connection ) ;
transaction_maybe_emit_closed ( self ) ;
2015-08-18 23:14:34 +03:00
}
2015-08-17 20:42:03 +03:00
static gboolean
transaction_new_connection_cb ( GDBusServer * server ,
GDBusConnection * connection ,
2015-08-24 22:44:40 +03:00
RpmostreedTransaction * self )
2015-08-17 20:42:03 +03:00
{
2015-08-24 22:44:40 +03:00
RpmostreedTransactionPrivate * priv = rpmostreed_transaction_get_private ( self ) ;
2015-08-17 20:42:03 +03:00
GError * local_error = NULL ;
g_dbus_interface_skeleton_export ( G_DBUS_INTERFACE_SKELETON ( self ) ,
connection , " / " , & local_error ) ;
if ( local_error ! = NULL )
{
g_critical ( " Failed to export interface: %s " , local_error - > message ) ;
g_clear_error ( & local_error ) ;
return FALSE ;
}
2015-08-18 23:14:34 +03:00
g_signal_connect_object ( connection ,
" closed " ,
G_CALLBACK ( transaction_connection_closed_cb ) ,
self , 0 ) ;
2015-08-26 19:57:02 +03:00
g_hash_table_add ( priv - > peer_connections , g_object_ref ( connection ) ) ;
2015-08-17 20:42:03 +03:00
2015-08-20 22:00:43 +03:00
g_debug ( " %s (%p): Client connected " ,
G_OBJECT_TYPE_NAME ( self ) , self ) ;
2015-08-17 20:42:03 +03:00
return TRUE ;
}
2015-07-23 18:30:33 +03:00
static void
transaction_owner_vanished_cb ( GDBusConnection * connection ,
const char * name ,
gpointer user_data )
{
2015-08-24 22:44:40 +03:00
RpmostreedTransaction * self = RPMOSTREED_TRANSACTION ( user_data ) ;
RpmostreedTransactionPrivate * priv = rpmostreed_transaction_get_private ( self ) ;
2015-07-23 18:30:33 +03:00
2015-08-13 19:53:58 +03:00
if ( priv - > watch_id > 0 )
2015-07-23 18:30:33 +03:00
{
2015-08-13 19:53:58 +03:00
g_bus_unwatch_name ( priv - > watch_id ) ;
priv - > watch_id = 0 ;
2015-07-23 18:30:33 +03:00
/* Emit the signal AFTER unwatching the bus name, since this
* may finalize the transaction and invalidate the watch_id . */
2015-08-26 19:57:02 +03:00
g_signal_emit ( self , signals [ CLOSED ] , 0 ) ;
2015-07-23 18:30:33 +03:00
}
}
static void
transaction_progress_changed_cb ( OstreeAsyncProgress * progress ,
RPMOSTreeTransaction * transaction )
{
guint64 start_time = ostree_async_progress_get_uint64 ( progress , " start-time " ) ;
guint64 elapsed_secs = 0 ;
guint outstanding_fetches = ostree_async_progress_get_uint ( progress , " outstanding-fetches " ) ;
guint outstanding_writes = ostree_async_progress_get_uint ( progress , " outstanding-writes " ) ;
guint n_scanned_metadata = ostree_async_progress_get_uint ( progress , " scanned-metadata " ) ;
guint metadata_fetched = ostree_async_progress_get_uint ( progress , " metadata-fetched " ) ;
guint outstanding_metadata_fetches = ostree_async_progress_get_uint ( progress , " outstanding-metadata-fetches " ) ;
guint total_delta_parts = ostree_async_progress_get_uint ( progress , " total-delta-parts " ) ;
guint fetched_delta_parts = ostree_async_progress_get_uint ( progress , " fetched-delta-parts " ) ;
guint total_delta_superblocks = ostree_async_progress_get_uint ( progress , " total-delta-superblocks " ) ;
guint64 total_delta_part_size = ostree_async_progress_get_uint64 ( progress , " total-delta-part-size " ) ;
guint fetched = ostree_async_progress_get_uint ( progress , " fetched " ) ;
guint requested = ostree_async_progress_get_uint ( progress , " requested " ) ;
guint64 bytes_sec = 0 ;
guint64 bytes_transferred = ostree_async_progress_get_uint64 ( progress , " bytes-transferred " ) ;
GVariant * arg_time ;
GVariant * arg_outstanding ;
GVariant * arg_metadata ;
GVariant * arg_delta ;
GVariant * arg_content ;
GVariant * arg_transfer ;
2015-11-23 20:03:11 +03:00
g_autofree gchar * status = NULL ;
2015-07-23 18:30:33 +03:00
/* If there is a status that is all we output */
status = ostree_async_progress_get_status ( progress ) ;
if ( status ) {
rpmostree_transaction_emit_message ( transaction , g_strdup ( status ) ) ;
return ;
}
if ( start_time )
{
guint64 elapsed_secs = ( g_get_monotonic_time ( ) - start_time ) / G_USEC_PER_SEC ;
if ( elapsed_secs )
bytes_sec = bytes_transferred / elapsed_secs ;
}
arg_time = g_variant_new ( " (tt) " ,
start_time ,
elapsed_secs ) ;
arg_outstanding = g_variant_new ( " (uu) " ,
outstanding_fetches ,
outstanding_writes ) ;
arg_metadata = g_variant_new ( " (uuu) " ,
n_scanned_metadata ,
metadata_fetched ,
outstanding_metadata_fetches ) ;
arg_delta = g_variant_new ( " (uuut) " ,
total_delta_parts ,
fetched_delta_parts ,
total_delta_superblocks ,
total_delta_part_size ) ;
arg_content = g_variant_new ( " (uu) " ,
fetched ,
requested ) ;
arg_transfer = g_variant_new ( " (tt) " ,
bytes_transferred ,
bytes_sec ) ;
/* This sinks the floating GVariant refs (I think...). */
rpmostree_transaction_emit_download_progress ( transaction ,
arg_time ,
arg_outstanding ,
arg_metadata ,
arg_delta ,
arg_content ,
arg_transfer ) ;
}
static void
transaction_gpg_verify_result_cb ( OstreeRepo * repo ,
const char * checksum ,
OstreeGpgVerifyResult * result ,
RPMOSTreeTransaction * transaction )
{
guint n , i ;
GVariantBuilder builder ;
g_variant_builder_init ( & builder , G_VARIANT_TYPE ( " av " ) ) ;
n = ostree_gpg_verify_result_count_all ( result ) ;
for ( i = 0 ; i < n ; i + + )
{
g_variant_builder_add ( & builder , " v " ,
ostree_gpg_verify_result_get_all ( result , i ) ) ;
}
rpmostree_transaction_emit_signature_progress ( transaction ,
g_variant_builder_end ( & builder ) ,
g_strdup ( checksum ) ) ;
}
2015-08-13 20:17:01 +03:00
static void
transaction_execute_thread ( GTask * task ,
gpointer source_object ,
gpointer task_data ,
GCancellable * cancellable )
{
2015-08-24 22:44:40 +03:00
RpmostreedTransaction * self = RPMOSTREED_TRANSACTION ( source_object ) ;
RpmostreedTransactionClass * class = RPMOSTREED_TRANSACTION_GET_CLASS ( self ) ;
2015-08-13 20:17:01 +03:00
gboolean success = TRUE ;
GError * local_error = NULL ;
2016-03-06 22:13:48 +03:00
g_autoptr ( GMainContext ) mctx = g_main_context_new ( ) ;
/* libostree iterates and calls quit on main loop
* so we need to run in our own context . Having a different
* main context for worker threads should be standard practice
* anyways .
*/
g_main_context_push_thread_default ( mctx ) ;
2015-08-13 20:17:01 +03:00
if ( class - > execute ! = NULL )
success = class - > execute ( self , cancellable , & local_error ) ;
if ( local_error ! = NULL )
g_task_return_error ( task , local_error ) ;
else
g_task_return_boolean ( task , success ) ;
2016-03-06 22:13:48 +03:00
/* Clean up context */
g_main_context_pop_thread_default ( mctx ) ;
2015-08-13 20:17:01 +03:00
}
static void
transaction_execute_done_cb ( GObject * source_object ,
GAsyncResult * result ,
gpointer user_data )
{
2015-08-24 22:44:40 +03:00
RpmostreedTransaction * self = RPMOSTREED_TRANSACTION ( source_object ) ;
RpmostreedTransactionPrivate * priv = rpmostreed_transaction_get_private ( self ) ;
2015-08-18 23:14:34 +03:00
const char * error_message = NULL ;
2015-08-13 20:17:01 +03:00
gboolean success ;
GError * local_error = NULL ;
success = g_task_propagate_boolean ( G_TASK ( result ) , & local_error ) ;
2016-03-04 19:34:10 +03:00
if ( success )
{
if ( ! rpmostreed_sysroot_reload ( rpmostreed_sysroot_get ( ) , & local_error ) )
success = FALSE ;
}
2015-08-13 20:17:01 +03:00
/* Sanity check */
g_warn_if_fail ( ( success & & local_error = = NULL ) | |
( ! success & & local_error ! = NULL ) ) ;
if ( local_error ! = NULL )
2015-08-18 23:14:34 +03:00
error_message = local_error - > message ;
2015-08-13 20:17:01 +03:00
2015-08-18 23:14:34 +03:00
if ( error_message = = NULL )
error_message = " " ;
2015-08-13 20:17:01 +03:00
2015-08-20 22:00:43 +03:00
g_debug ( " %s (%p): Finished%s%s%s " ,
G_OBJECT_TYPE_NAME ( self ) , self ,
success ? " " : " (error: " ,
success ? " " : error_message ,
success ? " " : " ) " ) ;
2015-08-18 23:14:34 +03:00
rpmostree_transaction_emit_finished ( RPMOSTREE_TRANSACTION ( self ) ,
success , error_message ) ;
2015-08-26 19:57:02 +03:00
/* Stash the Finished signal parameters in case we need
* to emit the signal again on subsequent new connections . */
priv - > finished_params = g_variant_new ( " (bs) " , success , error_message ) ;
g_variant_ref_sink ( priv - > finished_params ) ;
g_object_notify ( G_OBJECT ( self ) , " active " ) ;
transaction_maybe_emit_closed ( self ) ;
2015-08-13 20:17:01 +03:00
}
2015-07-23 18:30:33 +03:00
static void
transaction_set_property ( GObject * object ,
guint property_id ,
const GValue * value ,
GParamSpec * pspec )
{
2015-08-24 22:44:40 +03:00
RpmostreedTransaction * self = RPMOSTREED_TRANSACTION ( object ) ;
RpmostreedTransactionPrivate * priv = rpmostreed_transaction_get_private ( self ) ;
2015-07-23 18:30:33 +03:00
switch ( property_id )
{
2015-08-17 00:41:48 +03:00
case PROP_INVOCATION :
priv - > invocation = g_value_dup_object ( value ) ;
2015-08-13 17:56:06 +03:00
case PROP_SYSROOT :
2015-08-13 19:53:58 +03:00
priv - > sysroot = g_value_dup_object ( value ) ;
2015-08-13 17:56:06 +03:00
break ;
2015-07-23 18:30:33 +03:00
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , property_id , pspec ) ;
break ;
}
}
static void
transaction_get_property ( GObject * object ,
guint property_id ,
GValue * value ,
GParamSpec * pspec )
{
2015-08-24 22:44:40 +03:00
RpmostreedTransaction * self = RPMOSTREED_TRANSACTION ( object ) ;
RpmostreedTransactionPrivate * priv = rpmostreed_transaction_get_private ( self ) ;
2015-07-23 18:30:33 +03:00
switch ( property_id )
{
2015-08-17 00:41:48 +03:00
case PROP_INVOCATION :
g_value_set_object ( value , priv - > invocation ) ;
break ;
2015-08-13 17:56:06 +03:00
case PROP_SYSROOT :
2015-08-13 19:53:58 +03:00
g_value_set_object ( value , priv - > sysroot ) ;
2015-08-13 17:56:06 +03:00
break ;
2015-07-23 18:30:33 +03:00
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , property_id , pspec ) ;
break ;
}
}
static void
transaction_dispose ( GObject * object )
{
2015-08-24 22:44:40 +03:00
RpmostreedTransaction * self = RPMOSTREED_TRANSACTION ( object ) ;
RpmostreedTransactionPrivate * priv = rpmostreed_transaction_get_private ( self ) ;
2015-07-23 18:30:33 +03:00
2015-08-13 19:53:58 +03:00
if ( priv - > sysroot ! = NULL )
ostree_sysroot_unlock ( priv - > sysroot ) ;
2015-08-13 17:56:06 +03:00
2015-08-26 19:57:02 +03:00
g_hash_table_remove_all ( priv - > peer_connections ) ;
2015-08-17 00:41:48 +03:00
g_clear_object ( & priv - > invocation ) ;
2015-08-13 19:53:58 +03:00
g_clear_object ( & priv - > cancellable ) ;
g_clear_object ( & priv - > sysroot ) ;
2015-08-17 20:42:03 +03:00
g_clear_object ( & priv - > server ) ;
2015-08-26 19:57:02 +03:00
g_clear_pointer ( & priv - > finished_params , ( GDestroyNotify ) g_variant_unref ) ;
2015-07-23 18:30:33 +03:00
2015-08-24 22:44:40 +03:00
G_OBJECT_CLASS ( rpmostreed_transaction_parent_class ) - > dispose ( object ) ;
2015-07-23 18:30:33 +03:00
}
static void
transaction_finalize ( GObject * object )
{
2015-08-24 22:44:40 +03:00
RpmostreedTransaction * self = RPMOSTREED_TRANSACTION ( object ) ;
RpmostreedTransactionPrivate * priv = rpmostreed_transaction_get_private ( self ) ;
2015-07-23 18:30:33 +03:00
2015-08-20 22:00:43 +03:00
g_debug ( " %s (%p): Finalized " , G_OBJECT_TYPE_NAME ( self ) , self ) ;
2015-08-13 19:53:58 +03:00
if ( priv - > watch_id > 0 )
g_bus_unwatch_name ( priv - > watch_id ) ;
2015-07-23 18:30:33 +03:00
2015-08-26 19:57:02 +03:00
g_hash_table_destroy ( priv - > peer_connections ) ;
2015-08-24 22:44:40 +03:00
G_OBJECT_CLASS ( rpmostreed_transaction_parent_class ) - > finalize ( object ) ;
2015-07-23 18:30:33 +03:00
}
2015-08-17 00:41:48 +03:00
static void
transaction_constructed ( GObject * object )
{
2015-08-24 22:44:40 +03:00
RpmostreedTransaction * self = RPMOSTREED_TRANSACTION ( object ) ;
RpmostreedTransactionPrivate * priv = rpmostreed_transaction_get_private ( self ) ;
2015-08-17 00:41:48 +03:00
2015-08-24 22:44:40 +03:00
G_OBJECT_CLASS ( rpmostreed_transaction_parent_class ) - > constructed ( object ) ;
2015-08-17 00:41:48 +03:00
if ( priv - > invocation ! = NULL )
{
GDBusConnection * connection ;
const char * sender ;
connection = g_dbus_method_invocation_get_connection ( priv - > invocation ) ;
sender = g_dbus_method_invocation_get_sender ( priv - > invocation ) ;
2015-08-26 18:04:51 +03:00
/* Watch the sender's bus name until the transaction is started.
* This guards against a process initiating a transaction but then
* terminating before calling Start ( ) . If the bus name vanishes
* during this time , we abort the transaction . */
2015-08-17 00:41:48 +03:00
priv - > watch_id = g_bus_watch_name_on_connection ( connection ,
sender ,
G_BUS_NAME_WATCHER_FLAGS_NONE ,
NULL ,
transaction_owner_vanished_cb ,
self ,
NULL ) ;
}
}
2015-08-13 17:03:56 +03:00
static gboolean
transaction_initable_init ( GInitable * initable ,
GCancellable * cancellable ,
GError * * error )
{
2015-08-24 22:44:40 +03:00
RpmostreedTransaction * self = RPMOSTREED_TRANSACTION ( initable ) ;
RpmostreedTransactionPrivate * priv = rpmostreed_transaction_get_private ( self ) ;
2015-08-17 20:42:03 +03:00
g_autofree char * guid = NULL ;
2015-08-13 17:56:06 +03:00
gboolean ret = FALSE ;
2015-08-13 17:03:56 +03:00
if ( G_IS_CANCELLABLE ( cancellable ) )
2015-08-13 19:53:58 +03:00
priv - > cancellable = g_object_ref ( cancellable ) ;
2015-08-13 17:03:56 +03:00
2015-08-17 20:42:03 +03:00
/* Set up a private D-Bus server over which to emit
* progress and informational messages to the caller . */
guid = g_dbus_generate_guid ( ) ;
priv - > server = g_dbus_server_new_sync ( " unix:tmpdir=/tmp/rpm-ostree " ,
G_DBUS_SERVER_FLAGS_NONE ,
guid ,
NULL ,
cancellable ,
error ) ;
if ( priv - > server = = NULL )
goto out ;
g_signal_connect_object ( priv - > server ,
" new-connection " ,
G_CALLBACK ( transaction_new_connection_cb ) ,
self , 0 ) ;
2015-08-13 19:53:58 +03:00
if ( priv - > sysroot ! = NULL )
2015-08-13 17:56:06 +03:00
{
gboolean lock_acquired = FALSE ;
2015-08-13 19:53:58 +03:00
if ( ! ostree_sysroot_try_lock ( priv - > sysroot , & lock_acquired , error ) )
2015-08-13 17:56:06 +03:00
goto out ;
if ( ! lock_acquired )
{
g_set_error_literal ( error , G_IO_ERROR , G_IO_ERROR_BUSY ,
" System transaction in progress " ) ;
goto out ;
}
}
2015-08-17 20:42:03 +03:00
g_dbus_server_start ( priv - > server ) ;
2015-08-20 22:00:43 +03:00
g_debug ( " %s (%p): Initialized, listening on %s " ,
G_OBJECT_TYPE_NAME ( self ) , self ,
2015-08-24 22:44:40 +03:00
rpmostreed_transaction_get_client_address ( self ) ) ;
2015-08-20 22:00:43 +03:00
2015-08-13 17:56:06 +03:00
ret = TRUE ;
out :
return ret ;
2015-08-13 17:03:56 +03:00
}
2015-07-23 18:30:33 +03:00
static gboolean
transaction_handle_cancel ( RPMOSTreeTransaction * transaction ,
GDBusMethodInvocation * invocation )
{
2015-08-24 22:44:40 +03:00
RpmostreedTransaction * self = RPMOSTREED_TRANSACTION ( transaction ) ;
RpmostreedTransactionPrivate * priv = rpmostreed_transaction_get_private ( self ) ;
2015-07-23 18:30:33 +03:00
2015-08-20 22:00:43 +03:00
g_debug ( " %s (%p): Cancelled " , G_OBJECT_TYPE_NAME ( self ) , self ) ;
2015-08-18 18:42:22 +03:00
g_cancellable_cancel ( priv - > cancellable ) ;
2015-08-26 19:57:02 +03:00
2015-08-18 18:42:22 +03:00
rpmostree_transaction_complete_cancel ( transaction , invocation ) ;
2015-07-23 18:30:33 +03:00
return TRUE ;
}
2015-08-14 18:17:06 +03:00
static gboolean
transaction_handle_start ( RPMOSTreeTransaction * transaction ,
GDBusMethodInvocation * invocation )
{
2015-08-24 22:44:40 +03:00
RpmostreedTransaction * self = RPMOSTREED_TRANSACTION ( transaction ) ;
RpmostreedTransactionPrivate * priv = rpmostreed_transaction_get_private ( self ) ;
2015-08-26 18:29:06 +03:00
gboolean started = FALSE ;
2015-08-14 18:17:06 +03:00
2015-08-26 18:04:51 +03:00
/* The bus name watch ID doubles as a "not-yet-started" flag.
* Once started the transaction proceeds independently of the
* initiating process whose bus name we were watching . */
if ( priv - > watch_id > 0 )
2015-08-14 18:17:06 +03:00
{
2015-08-13 20:17:01 +03:00
GTask * task ;
2015-08-26 18:29:06 +03:00
started = TRUE ;
2015-08-20 22:00:43 +03:00
g_debug ( " %s (%p): Started " , G_OBJECT_TYPE_NAME ( self ) , self ) ;
2015-08-26 18:04:51 +03:00
g_bus_unwatch_name ( priv - > watch_id ) ;
priv - > watch_id = 0 ;
2015-08-14 18:17:06 +03:00
2015-08-13 20:17:01 +03:00
task = g_task_new ( transaction ,
priv - > cancellable ,
transaction_execute_done_cb ,
NULL ) ;
g_task_run_in_thread ( task , transaction_execute_thread ) ;
g_object_unref ( task ) ;
2015-08-26 18:04:51 +03:00
}
2015-08-14 18:17:06 +03:00
2015-08-26 18:29:06 +03:00
rpmostree_transaction_complete_start ( transaction , invocation , started ) ;
2015-08-26 19:57:02 +03:00
/* If the transaction is already finished, emit the
* Finished signal again but only on this connection . */
if ( priv - > finished_params ! = NULL )
{
GDBusConnection * connection ;
const char * object_path ;
const char * interface_name ;
GError * local_error = NULL ;
connection = g_dbus_method_invocation_get_connection ( invocation ) ;
object_path = g_dbus_method_invocation_get_object_path ( invocation ) ;
interface_name = g_dbus_method_invocation_get_interface_name ( invocation ) ;
g_dbus_connection_emit_signal ( connection ,
NULL ,
object_path ,
interface_name ,
" Finished " ,
priv - > finished_params ,
& local_error ) ;
if ( local_error ! = NULL )
{
g_critical ( " %s " , local_error - > message ) ;
g_clear_error ( & local_error ) ;
}
}
2015-08-14 18:17:06 +03:00
return TRUE ;
}
2015-07-23 18:30:33 +03:00
static void
2015-08-24 22:44:40 +03:00
rpmostreed_transaction_class_init ( RpmostreedTransactionClass * class )
2015-07-23 18:30:33 +03:00
{
GObjectClass * object_class ;
2015-08-24 22:44:40 +03:00
g_type_class_add_private ( class , sizeof ( RpmostreedTransactionPrivate ) ) ;
2015-08-13 19:53:58 +03:00
2015-07-23 18:30:33 +03:00
object_class = G_OBJECT_CLASS ( class ) ;
object_class - > set_property = transaction_set_property ;
object_class - > get_property = transaction_get_property ;
object_class - > dispose = transaction_dispose ;
object_class - > finalize = transaction_finalize ;
2015-08-17 00:41:48 +03:00
object_class - > constructed = transaction_constructed ;
2015-08-26 19:57:02 +03:00
g_object_class_install_property ( object_class ,
PROP_ACTIVE ,
g_param_spec_boolean ( " active " ,
" Active " ,
" Whether the transaction is active (unfinished) " ,
TRUE ,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS ) ) ;
2015-08-17 00:41:48 +03:00
g_object_class_install_property ( object_class ,
PROP_INVOCATION ,
g_param_spec_object ( " invocation " ,
" Invocation " ,
" D-Bus method invocation " ,
G_TYPE_DBUS_METHOD_INVOCATION ,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS ) ) ;
2015-07-23 18:30:33 +03:00
2015-08-13 17:56:06 +03:00
g_object_class_install_property ( object_class ,
PROP_SYSROOT ,
g_param_spec_object ( " sysroot " ,
" Sysroot " ,
" An OstreeSysroot instance " ,
OSTREE_TYPE_SYSROOT ,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS ) ) ;
2015-08-18 23:14:34 +03:00
signals [ CLOSED ] = g_signal_new ( " closed " ,
2015-08-24 22:44:40 +03:00
RPMOSTREED_TYPE_TRANSACTION ,
2015-08-18 23:14:34 +03:00
G_SIGNAL_RUN_LAST ,
0 , NULL , NULL , NULL ,
G_TYPE_NONE , 0 ) ;
2015-07-23 18:30:33 +03:00
}
static void
2015-08-24 22:44:40 +03:00
rpmostreed_transaction_initable_iface_init ( GInitableIface * iface )
2015-08-13 17:03:56 +03:00
{
iface - > init = transaction_initable_init ;
}
static void
2015-08-24 22:44:40 +03:00
rpmostreed_transaction_dbus_iface_init ( RPMOSTreeTransactionIface * iface )
2015-07-23 18:30:33 +03:00
{
iface - > handle_cancel = transaction_handle_cancel ;
2015-08-14 18:17:06 +03:00
iface - > handle_start = transaction_handle_start ;
2015-07-23 18:30:33 +03:00
}
static void
2015-08-24 22:44:40 +03:00
rpmostreed_transaction_init ( RpmostreedTransaction * self )
2015-07-23 18:30:33 +03:00
{
2015-08-13 19:53:58 +03:00
self - > priv = G_TYPE_INSTANCE_GET_PRIVATE ( self ,
2015-08-24 22:44:40 +03:00
RPMOSTREED_TYPE_TRANSACTION ,
RpmostreedTransactionPrivate ) ;
2015-08-26 19:57:02 +03:00
self - > priv - > peer_connections = g_hash_table_new_full ( g_direct_hash ,
g_direct_equal ,
g_object_unref ,
NULL ) ;
}
gboolean
rpmostreed_transaction_get_active ( RpmostreedTransaction * transaction )
{
RpmostreedTransactionPrivate * priv ;
g_return_val_if_fail ( RPMOSTREED_IS_TRANSACTION ( transaction ) , FALSE ) ;
priv = rpmostreed_transaction_get_private ( transaction ) ;
return ( priv - > finished_params = = NULL ) ;
2015-07-23 18:30:33 +03:00
}
2015-08-13 17:56:06 +03:00
OstreeSysroot *
2015-08-24 22:44:40 +03:00
rpmostreed_transaction_get_sysroot ( RpmostreedTransaction * transaction )
2015-08-13 17:56:06 +03:00
{
2015-08-24 22:44:40 +03:00
RpmostreedTransactionPrivate * priv ;
2015-08-13 17:56:06 +03:00
2015-08-24 22:44:40 +03:00
g_return_val_if_fail ( RPMOSTREED_IS_TRANSACTION ( transaction ) , NULL ) ;
2015-08-13 17:56:06 +03:00
2015-08-24 22:44:40 +03:00
priv = rpmostreed_transaction_get_private ( transaction ) ;
2015-08-13 17:56:06 +03:00
2015-08-13 19:53:58 +03:00
return priv - > sysroot ;
2015-08-13 17:56:06 +03:00
}
2015-08-24 21:28:09 +03:00
GDBusMethodInvocation *
2015-08-24 22:44:40 +03:00
rpmostreed_transaction_get_invocation ( RpmostreedTransaction * transaction )
2015-08-24 21:28:09 +03:00
{
2015-08-24 22:44:40 +03:00
RpmostreedTransactionPrivate * priv ;
2015-08-24 21:28:09 +03:00
2015-08-24 22:44:40 +03:00
g_return_val_if_fail ( RPMOSTREED_IS_TRANSACTION ( transaction ) , NULL ) ;
2015-08-24 21:28:09 +03:00
2015-08-24 22:44:40 +03:00
priv = rpmostreed_transaction_get_private ( transaction ) ;
2015-08-24 21:28:09 +03:00
return priv - > invocation ;
}
2015-08-17 20:42:03 +03:00
const char *
2015-08-24 22:44:40 +03:00
rpmostreed_transaction_get_client_address ( RpmostreedTransaction * transaction )
2015-08-17 20:42:03 +03:00
{
2015-08-24 22:44:40 +03:00
RpmostreedTransactionPrivate * priv ;
2015-08-17 20:42:03 +03:00
2015-08-24 22:44:40 +03:00
g_return_val_if_fail ( RPMOSTREED_IS_TRANSACTION ( transaction ) , NULL ) ;
2015-08-17 20:42:03 +03:00
2015-08-24 22:44:40 +03:00
priv = rpmostreed_transaction_get_private ( transaction ) ;
2015-08-17 20:42:03 +03:00
return g_dbus_server_get_client_address ( priv - > server ) ;
}
2015-07-23 18:30:33 +03:00
void
2015-08-24 22:44:40 +03:00
rpmostreed_transaction_emit_message_printf ( RpmostreedTransaction * transaction ,
const char * format ,
. . . )
2015-07-23 18:30:33 +03:00
{
2015-08-13 20:17:01 +03:00
g_autofree char * formatted_message = NULL ;
2015-07-23 18:30:33 +03:00
va_list args ;
2015-08-24 22:44:40 +03:00
g_return_if_fail ( RPMOSTREED_IS_TRANSACTION ( transaction ) ) ;
2015-07-23 18:30:33 +03:00
g_return_if_fail ( format ! = NULL ) ;
va_start ( args , format ) ;
2015-08-13 20:17:01 +03:00
formatted_message = g_strdup_vprintf ( format , args ) ;
2015-07-23 18:30:33 +03:00
va_end ( args ) ;
2015-08-13 20:17:01 +03:00
rpmostree_transaction_emit_message ( RPMOSTREE_TRANSACTION ( transaction ) ,
formatted_message ) ;
2015-07-23 18:30:33 +03:00
}
2015-08-27 18:14:50 +03:00
gboolean
rpmostreed_transaction_is_compatible ( RpmostreedTransaction * transaction ,
GDBusMethodInvocation * invocation )
{
RpmostreedTransactionPrivate * priv ;
const char * method_name_a ;
const char * method_name_b ;
GVariant * parameters_a ;
GVariant * parameters_b ;
g_return_val_if_fail ( RPMOSTREED_IS_TRANSACTION ( transaction ) , FALSE ) ;
g_return_val_if_fail ( G_IS_DBUS_METHOD_INVOCATION ( invocation ) , FALSE ) ;
priv = rpmostreed_transaction_get_private ( transaction ) ;
method_name_a = g_dbus_method_invocation_get_method_name ( priv - > invocation ) ;
method_name_b = g_dbus_method_invocation_get_method_name ( invocation ) ;
parameters_a = g_dbus_method_invocation_get_parameters ( priv - > invocation ) ;
parameters_b = g_dbus_method_invocation_get_parameters ( invocation ) ;
return g_str_equal ( method_name_a , method_name_b ) & &
g_variant_equal ( parameters_a , parameters_b ) ;
}
2015-07-23 18:30:33 +03:00
void
2015-08-24 22:44:40 +03:00
rpmostreed_transaction_connect_download_progress ( RpmostreedTransaction * transaction ,
OstreeAsyncProgress * progress )
2015-07-23 18:30:33 +03:00
{
2015-08-24 22:44:40 +03:00
g_return_if_fail ( RPMOSTREED_IS_TRANSACTION ( transaction ) ) ;
2015-07-23 18:30:33 +03:00
g_return_if_fail ( OSTREE_IS_ASYNC_PROGRESS ( progress ) ) ;
g_signal_connect_object ( progress ,
" changed " ,
G_CALLBACK ( transaction_progress_changed_cb ) ,
transaction , 0 ) ;
}
void
2015-08-24 22:44:40 +03:00
rpmostreed_transaction_connect_signature_progress ( RpmostreedTransaction * transaction ,
OstreeRepo * repo )
2015-07-23 18:30:33 +03:00
{
2015-08-24 22:44:40 +03:00
g_return_if_fail ( RPMOSTREED_IS_TRANSACTION ( transaction ) ) ;
2015-07-23 18:30:33 +03:00
g_return_if_fail ( OSTREE_REPO ( repo ) ) ;
g_signal_connect_object ( repo , " gpg-verify-result " ,
G_CALLBACK ( transaction_gpg_verify_result_cb ) ,
transaction , 0 ) ;
}