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
2016-03-02 00:51:16 +03:00
/* Get a currently unique (for this host) identifier for the
* deployment ; TODO - adding the deployment timestamp would make it
* persistently unique , needs API in libostree .
*/
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
{
g_return_val_if_fail ( OSTREE_IS_DEPLOYMENT ( deployment ) , NULL ) ;
2016-03-02 00:51:16 +03:00
return g_strdup_printf ( " %s-%s.%u " ,
ostree_deployment_get_osname ( deployment ) ,
ostree_deployment_get_csum ( deployment ) ,
ostree_deployment_get_deployserial ( deployment ) ) ;
2015-05-25 20:19:21 +03:00
}
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 ;
2015-12-29 16:14:04 +03:00
if ( remote )
{
if ( ! ostree_repo_remote_get_gpg_verify ( repo , remote , & gpg_verify , & error ) )
goto out ;
}
else
{
gpg_verify = FALSE ;
}
2015-05-25 20:19:21 +03:00
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
{
char * origin_refspec = NULL ;
2015-02-11 21:06:43 +03:00
rpmostreed_deployment_get_refspec_packages ( deployment , & origin_refspec , NULL ) ;
return origin_refspec ;
}
void
rpmostreed_deployment_get_refspec_packages ( OstreeDeployment * deployment ,
char * * out_refspec ,
char * * * out_packages )
{
GKeyFile * origin = NULL ; /* owned by deployment */
gsize len ;
g_return_if_fail ( out_refspec ! = NULL ) ;
2015-06-10 05:27:39 +03:00
origin = ostree_deployment_get_origin ( deployment ) ;
if ( ! origin )
2015-02-11 21:06:43 +03:00
{
* out_refspec = NULL ;
* out_packages = NULL ;
return ;
}
2015-06-10 05:27:39 +03:00
2015-02-11 21:06:43 +03:00
* out_refspec = g_key_file_get_string ( origin , " origin " , " refspec " , NULL ) ;
if ( ! * out_refspec )
* out_refspec = g_key_file_get_string ( origin , " origin " , " baserefspec " , NULL ) ;
2015-06-10 05:27:39 +03:00
2015-02-11 21:06:43 +03:00
if ( out_packages )
* out_packages = g_key_file_get_string_list ( origin , " packages " , " requested " , & len , NULL ) ;
2015-06-10 05:27:39 +03:00
}
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
2015-09-27 19:44:57 +03:00
static void
variant_add_commit_details ( GVariantDict * dict ,
2016-06-09 04:37:40 +03:00
GVariant * commit )
2015-05-25 20:19:21 +03:00
{
2015-09-27 19:44:57 +03:00
g_autoptr ( GVariant ) metadata = NULL ;
g_autofree gchar * version_commit = NULL ;
2015-05-25 20:19:21 +03:00
guint64 timestamp = 0 ;
2016-06-09 04:37:40 +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 ) ;
2015-09-27 19:44:57 +03:00
if ( version_commit ! = NULL )
g_variant_dict_insert ( dict , " version " , " s " , version_commit ) ;
if ( timestamp > 0 )
g_variant_dict_insert ( dict , " timestamp " , " t " , timestamp ) ;
}
GVariant *
rpmostreed_deployment_generate_variant ( OstreeDeployment * deployment ,
2016-06-25 00:40:46 +03:00
const char * booted_id ,
2016-06-09 04:37:40 +03:00
OstreeRepo * repo ,
GError * * error )
2015-09-27 19:44:57 +03:00
{
g_autoptr ( GVariant ) commit = NULL ;
g_autofree gchar * origin_refspec = NULL ;
2015-02-11 21:06:43 +03:00
g_auto ( GStrv ) origin_packages = NULL ;
2015-09-27 19:44:57 +03:00
g_autofree gchar * id = NULL ;
GVariant * sigs = NULL ; /* floating variant */
GVariantDict dict ;
const gchar * osname = ostree_deployment_get_osname ( deployment ) ;
const gchar * csum = ostree_deployment_get_csum ( deployment ) ;
gint serial = ostree_deployment_get_deployserial ( deployment ) ;
2016-06-09 04:37:40 +03:00
if ( ! ostree_repo_load_variant ( repo ,
OSTREE_OBJECT_TYPE_COMMIT ,
csum ,
& commit ,
error ) )
return NULL ;
2015-09-27 19:44:57 +03:00
id = rpmostreed_deployment_generate_id ( deployment ) ;
2015-05-25 20:19:21 +03:00
2015-02-11 21:06:43 +03:00
rpmostreed_deployment_get_refspec_packages ( deployment , & origin_refspec , & origin_packages ) ;
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 ) ;
2016-06-29 22:07:16 +03:00
if ( origin_packages ! = NULL & & g_strv_length ( origin_packages ) > 0 )
2016-06-09 04:45:25 +03:00
{
const char * parent = ostree_commit_get_parent ( commit ) ;
g_assert ( parent ) ;
g_variant_dict_insert ( & dict , " base-checksum " , " s " , parent ) ;
2016-06-23 18:16:27 +03:00
if ( origin_refspec )
sigs = rpmostreed_deployment_gpg_results ( repo , origin_refspec , parent ) ;
2016-06-09 04:45:25 +03:00
}
2016-06-23 18:16:27 +03:00
else if ( origin_refspec )
sigs = rpmostreed_deployment_gpg_results ( repo , origin_refspec , csum ) ;
2015-09-27 19:44:57 +03:00
2016-06-09 04:37:40 +03:00
variant_add_commit_details ( & dict , commit ) ;
2015-09-08 17:31:22 +03:00
if ( origin_refspec ! = NULL )
g_variant_dict_insert ( & dict , " origin " , " s " , origin_refspec ) ;
2015-02-11 21:06:43 +03:00
if ( origin_packages ! = NULL )
g_variant_dict_insert ( & dict , " packages " , " ^as " , origin_packages ) ;
2015-09-08 17:31:22 +03:00
if ( sigs ! = NULL )
g_variant_dict_insert_value ( & dict , " signatures " , sigs ) ;
2016-06-01 20:53:13 +03:00
g_variant_dict_insert ( & dict , " unlocked " , " s " ,
ostree_deployment_unlocked_state_to_string ( ostree_deployment_get_unlocked ( deployment ) ) ) ;
2016-06-25 00:40:46 +03:00
if ( booted_id ! = NULL )
g_variant_dict_insert ( & dict , " booted " , " b " , g_strcmp0 ( booted_id , id ) = = 0 ) ;
2015-09-08 17:31:22 +03:00
return g_variant_dict_end ( & dict ) ;
2015-05-25 20:19:21 +03:00
}
2015-06-11 05:17:49 +03:00
2015-09-27 19:44:57 +03:00
GVariant *
rpmostreed_commit_generate_cached_details_variant ( OstreeDeployment * deployment ,
OstreeRepo * repo ,
2016-06-09 04:37:40 +03:00
const gchar * refspec ,
GError * * error )
2015-09-27 19:44:57 +03:00
{
2016-06-09 04:37:40 +03:00
g_autoptr ( GVariant ) commit = NULL ;
2015-09-27 19:44:57 +03:00
g_autofree gchar * origin_refspec = NULL ;
2016-06-27 19:25:57 +03:00
const gchar * head = NULL ;
2015-09-27 19:44:57 +03:00
const gchar * osname ;
GVariant * sigs = NULL ; /* floating variant */
GVariant * ret = NULL ; /* floating variant */
GVariantDict dict ;
osname = ostree_deployment_get_osname ( deployment ) ;
if ( refspec )
origin_refspec = g_strdup ( refspec ) ;
else
origin_refspec = rpmostreed_deployment_get_refspec ( deployment ) ;
if ( ! origin_refspec )
goto out ;
2016-06-27 19:25:57 +03:00
head = ostree_deployment_get_csum ( deployment ) ;
2016-06-09 04:37:40 +03:00
if ( ! ostree_repo_load_variant ( repo ,
OSTREE_OBJECT_TYPE_COMMIT ,
head ,
& commit ,
error ) )
return NULL ;
2015-09-27 19:44:57 +03:00
sigs = rpmostreed_deployment_gpg_results ( repo , origin_refspec , head ) ;
g_variant_dict_init ( & dict , NULL ) ;
if ( osname ! = NULL )
g_variant_dict_insert ( & dict , " osname " , " s " , osname ) ;
g_variant_dict_insert ( & dict , " checksum " , " s " , head ) ;
2016-06-09 04:37:40 +03:00
variant_add_commit_details ( & dict , commit ) ;
2015-09-27 19:44:57 +03:00
g_variant_dict_insert ( & dict , " origin " , " s " , origin_refspec ) ;
if ( sigs ! = NULL )
g_variant_dict_insert_value ( & dict , " signatures " , sigs ) ;
ret = g_variant_dict_end ( & dict ) ;
out :
return ret ;
}
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 ;
}