2015-05-25 20:19:21 +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
*/
2015-06-10 05:27:39 +03:00
# include "config.h"
2015-08-24 22:44:40 +03:00
# include "rpmostreed-deployment-utils.h"
2015-05-25 20:19:21 +03:00
2015-06-10 05:27:39 +03:00
# include <libglnx.h>
2015-05-25 20:19:21 +03:00
char *
2015-08-24 22:44:40 +03:00
rpmostreed_deployment_generate_id ( OstreeDeployment * deployment )
2015-05-25 20:19:21 +03:00
{
const char * osname ;
guint hash ;
g_return_val_if_fail ( OSTREE_IS_DEPLOYMENT ( deployment ) , NULL ) ;
osname = ostree_deployment_get_osname ( deployment ) ;
hash = ostree_deployment_hash ( deployment ) ;
return g_strdup_printf ( " %s_%u " , osname , hash ) ;
}
2015-06-11 05:17:49 +03:00
OstreeDeployment *
2015-08-24 22:44:40 +03:00
rpmostreed_deployment_get_for_id ( OstreeSysroot * sysroot ,
const gchar * deploy_id )
2015-06-11 05:17:49 +03:00
{
2015-07-16 21:11:35 +03:00
g_autoptr ( GPtrArray ) deployments = NULL ;
2015-06-11 05:17:49 +03:00
guint i ;
OstreeDeployment * deployment = NULL ;
deployments = ostree_sysroot_get_deployments ( sysroot ) ;
if ( deployments = = NULL )
goto out ;
for ( i = 0 ; i < deployments - > len ; i + + )
{
2015-08-24 22:44:40 +03:00
g_autofree gchar * id = rpmostreed_deployment_generate_id ( deployments - > pdata [ i ] ) ;
2015-06-11 05:17:49 +03:00
if ( g_strcmp0 ( deploy_id , id ) = = 0 ) {
deployment = g_object_ref ( deployments - > pdata [ i ] ) ;
}
}
out :
return deployment ;
}
2015-05-25 20:19:21 +03:00
static GVariant *
2015-08-24 22:44:40 +03:00
rpmostreed_deployment_gpg_results ( OstreeRepo * repo ,
const gchar * origin_refspec ,
const gchar * csum )
2015-05-25 20:19:21 +03:00
{
GError * error = NULL ;
GVariant * ret = NULL ;
2015-06-10 05:27:39 +03:00
g_autofree gchar * remote = NULL ;
glnx_unref_object OstreeGpgVerifyResult * result = NULL ;
2015-05-25 20:19:21 +03:00
guint n_sigs , i ;
gboolean gpg_verify ;
GVariantBuilder builder ;
g_variant_builder_init ( & builder , G_VARIANT_TYPE ( " av " ) ) ;
if ( ! ostree_parse_refspec ( origin_refspec , & remote , NULL , & error ) )
goto out ;
if ( ! ostree_repo_remote_get_gpg_verify ( repo , remote , & gpg_verify , & error ) )
goto out ;
if ( ! gpg_verify )
goto out ;
result = ostree_repo_verify_commit_ext ( repo , csum , NULL , NULL ,
NULL , & error ) ;
if ( ! result )
goto out ;
n_sigs = ostree_gpg_verify_result_count_all ( result ) ;
if ( n_sigs < 1 )
goto out ;
for ( i = 0 ; i < n_sigs ; i + + )
{
g_variant_builder_add ( & builder , " v " ,
ostree_gpg_verify_result_get_all ( result , i ) ) ;
}
ret = g_variant_builder_end ( & builder ) ;
out :
/* NOT_FOUND just means the commit is not signed. */
if ( error & & ! g_error_matches ( error , G_IO_ERROR , G_IO_ERROR_NOT_FOUND ) )
g_warning ( " error loading gpg verify result %s " , error - > message ) ;
g_clear_error ( & error ) ;
return ret ;
}
2015-06-10 05:27:39 +03:00
char *
2015-08-24 22:44:40 +03:00
rpmostreed_deployment_get_refspec ( OstreeDeployment * deployment )
2015-06-10 05:27:39 +03:00
{
2015-07-16 21:11:35 +03:00
GKeyFile * origin = NULL ; /* owned by deployment */
2015-06-10 05:27:39 +03:00
char * origin_refspec = NULL ;
origin = ostree_deployment_get_origin ( deployment ) ;
if ( ! origin )
goto out ;
origin_refspec = g_key_file_get_string ( origin , " origin " , " refspec " , NULL ) ;
out :
return origin_refspec ;
}
GVariant *
2015-08-24 22:44:40 +03:00
rpmostreed_deployment_generate_blank_variant ( void )
2015-06-10 05:27:39 +03:00
{
2015-09-08 17:31:22 +03:00
GVariantDict dict ;
g_variant_dict_init ( & dict , NULL ) ;
return g_variant_dict_end ( & dict ) ;
2015-06-10 05:27:39 +03:00
}
2015-05-25 20:19:21 +03:00
GVariant *
2015-08-24 22:44:40 +03:00
rpmostreed_deployment_generate_variant ( OstreeDeployment * deployment ,
OstreeRepo * repo )
2015-05-25 20:19:21 +03:00
{
2015-07-16 21:11:35 +03:00
g_autoptr ( GVariant ) commit = NULL ;
2015-05-25 20:19:21 +03:00
2015-06-10 05:27:39 +03:00
g_autofree gchar * origin_refspec = NULL ;
g_autofree gchar * version_commit = NULL ;
g_autofree gchar * id = NULL ;
2015-05-25 20:19:21 +03:00
2015-07-16 21:11:35 +03:00
GVariant * sigs = NULL ; /* floating variant */
2015-05-25 20:19:21 +03:00
GError * error = NULL ;
2015-09-08 17:31:22 +03:00
GVariantDict dict ;
2015-05-25 20:19:21 +03:00
guint64 timestamp = 0 ;
const gchar * osname = ostree_deployment_get_osname ( deployment ) ;
const gchar * csum = ostree_deployment_get_csum ( deployment ) ;
gint serial = ostree_deployment_get_deployserial ( deployment ) ;
2015-08-24 22:44:40 +03:00
id = rpmostreed_deployment_generate_id ( deployment ) ;
2015-05-25 20:19:21 +03:00
if ( ostree_repo_load_variant ( repo ,
OSTREE_OBJECT_TYPE_COMMIT ,
csum ,
& commit ,
& error ) )
{
2015-07-16 21:11:35 +03:00
g_autoptr ( GVariant ) metadata = NULL ;
2015-05-25 20:19:21 +03:00
timestamp = ostree_commit_get_timestamp ( commit ) ;
metadata = g_variant_get_child_value ( commit , 0 ) ;
if ( metadata ! = NULL )
g_variant_lookup ( metadata , " version " , " s " , & version_commit ) ;
}
else
{
g_warning ( " Error loading commit %s " , error - > message ) ;
}
g_clear_error ( & error ) ;
2015-08-24 22:44:40 +03:00
origin_refspec = rpmostreed_deployment_get_refspec ( deployment ) ;
2015-06-10 05:27:39 +03:00
if ( origin_refspec )
2015-08-24 22:44:40 +03:00
sigs = rpmostreed_deployment_gpg_results ( repo , origin_refspec , csum ) ;
2015-05-25 20:19:21 +03:00
2015-09-08 17:31:22 +03:00
g_variant_dict_init ( & dict , NULL ) ;
g_variant_dict_insert ( & dict , " id " , " s " , id ) ;
if ( osname ! = NULL )
g_variant_dict_insert ( & dict , " osname " , " s " , osname ) ;
g_variant_dict_insert ( & dict , " serial " , " i " , serial ) ;
g_variant_dict_insert ( & dict , " checksum " , " s " , csum ) ;
if ( version_commit ! = NULL )
g_variant_dict_insert ( & dict , " version " , " s " , version_commit ) ;
if ( timestamp > 0 )
g_variant_dict_insert ( & dict , " timestamp " , " t " , timestamp ) ;
if ( origin_refspec ! = NULL )
g_variant_dict_insert ( & dict , " origin " , " s " , origin_refspec ) ;
if ( sigs ! = NULL )
g_variant_dict_insert_value ( & dict , " signatures " , sigs ) ;
return g_variant_dict_end ( & dict ) ;
2015-05-25 20:19:21 +03:00
}
2015-06-11 05:17:49 +03:00
gint
2015-08-24 22:44:40 +03:00
rpmostreed_rollback_deployment_index ( const gchar * name ,
OstreeSysroot * ot_sysroot ,
GError * * error )
2015-06-11 05:17:49 +03:00
{
2015-07-16 21:11:35 +03:00
g_autoptr ( GPtrArray ) deployments = NULL ;
2015-06-11 05:17:49 +03:00
glnx_unref_object OstreeDeployment * merge_deployment = NULL ;
gint index_to_prepend = - 1 ;
gint merge_index = - 1 ;
gint previous_index = - 1 ;
guint i ;
merge_deployment = ostree_sysroot_get_merge_deployment ( ot_sysroot , name ) ;
if ( merge_deployment = = NULL )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" No deployments found for os %s " , name ) ;
goto out ;
}
deployments = ostree_sysroot_get_deployments ( ot_sysroot ) ;
if ( deployments - > len < 2 )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Found %u deployments, at least 2 required for rollback " ,
deployments - > len ) ;
goto out ;
}
g_assert ( merge_deployment ! = NULL ) ;
for ( i = 0 ; i < deployments - > len ; i + + )
{
if ( deployments - > pdata [ i ] = = merge_deployment )
merge_index = i ;
if ( g_strcmp0 ( ostree_deployment_get_osname ( deployments - > pdata [ i ] ) , name ) = = 0 & &
deployments - > pdata [ i ] ! = merge_deployment & &
previous_index < 0 )
{
previous_index = i ;
}
}
g_assert ( merge_index < deployments - > len ) ;
g_assert ( deployments - > pdata [ merge_index ] = = merge_deployment ) ;
/* If merge deployment is not booted assume we are using it. */
if ( merge_index = = 0 & & previous_index > 0 )
index_to_prepend = previous_index ;
else
index_to_prepend = merge_index ;
out :
return index_to_prepend ;
}