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"
2017-01-11 22:05:18 +03:00
# include "rpmostree-origin.h"
# include "rpmostree-util.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 ,
2016-07-21 23:28:20 +03:00
const gchar * csum ,
gboolean * out_enabled )
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 ;
2016-12-05 23:21:32 +03:00
g_auto ( GVariantBuilder ) builder ;
2015-05-25 20:19:21 +03:00
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
2016-07-21 23:28:20 +03:00
* out_enabled = gpg_verify ;
2015-05-25 20:19:21 +03:00
if ( ! gpg_verify )
goto out ;
2016-11-17 00:32:51 +03:00
# ifdef HAVE_OSTREE_REPO_VERIFY_COMMIT_FOR_REMOTE
result = ostree_repo_verify_commit_for_remote ( repo , csum , remote , NULL , & error ) ;
# else
result = ostree_repo_verify_commit_ext ( repo , csum , NULL , NULL , NULL , & error ) ;
# endif
2015-05-25 20:19:21 +03:00
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
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 ,
2017-01-27 07:31:53 +03:00
const char * prefix ,
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 )
2017-01-27 07:31:53 +03:00
g_variant_dict_insert ( dict , glnx_strjoina ( prefix ? : " " , " version " ) ,
" s " , version_commit ) ;
2015-09-27 19:44:57 +03:00
if ( timestamp > 0 )
2017-01-27 07:31:53 +03:00
g_variant_dict_insert ( dict , glnx_strjoina ( prefix ? : " " , " timestamp " ) ,
" t " , timestamp ) ;
2015-09-27 19:44:57 +03:00
}
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 ;
2017-01-11 22:05:18 +03:00
g_autoptr ( RpmOstreeOrigin ) origin = NULL ;
2015-09-27 19:44:57 +03:00
g_autofree gchar * id = NULL ;
2017-02-24 17:14:24 +03:00
g_autofree char * base_checksum = NULL ;
2015-09-27 19:44:57 +03:00
GVariant * sigs = NULL ; /* floating variant */
GVariantDict dict ;
2017-01-27 07:31:53 +03:00
const char * refspec ;
g_autofree char * pending_base_commitrev = NULL ;
2015-09-27 19:44:57 +03:00
const gchar * osname = ostree_deployment_get_osname ( deployment ) ;
const gchar * csum = ostree_deployment_get_csum ( deployment ) ;
gint serial = ostree_deployment_get_deployserial ( deployment ) ;
2016-10-25 20:43:50 +03:00
gboolean gpg_enabled = FALSE ;
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
2017-02-16 20:46:13 +03:00
origin = rpmostree_origin_parse_deployment ( deployment , error ) ;
2017-01-11 22:05:18 +03:00
if ( ! origin )
return NULL ;
2015-05-25 20:19:21 +03:00
2017-01-27 07:31:53 +03:00
refspec = rpmostree_origin_get_refspec ( origin ) ;
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 ) ;
2017-01-11 22:05:18 +03:00
if ( rpmostree_origin_is_locally_assembled ( origin ) )
2016-06-09 04:45:25 +03:00
{
2017-01-27 07:31:53 +03:00
base_checksum = ostree_commit_get_parent ( commit ) ;
g_assert ( base_checksum ) ;
g_variant_dict_insert ( & dict , " base-checksum " , " s " , base_checksum ) ;
2016-06-09 04:45:25 +03:00
}
2017-01-11 22:05:18 +03:00
else
2017-01-27 07:31:53 +03:00
{
2017-02-24 17:14:24 +03:00
base_checksum = g_strdup ( csum ) ;
2017-01-27 07:31:53 +03:00
}
sigs = rpmostreed_deployment_gpg_results ( repo , refspec , base_checksum , & gpg_enabled ) ;
variant_add_commit_details ( & dict , NULL , commit ) ;
if ( ! ostree_repo_resolve_rev ( repo , refspec , TRUE ,
& pending_base_commitrev , error ) )
return NULL ;
if ( pending_base_commitrev & & strcmp ( pending_base_commitrev , base_checksum ) ! = 0 )
{
g_autoptr ( GVariant ) pending_base_commit = NULL ;
if ( ! ostree_repo_load_variant ( repo ,
OSTREE_OBJECT_TYPE_COMMIT ,
pending_base_commitrev ,
& pending_base_commit ,
error ) )
return NULL ;
g_variant_dict_insert ( & dict , " pending-base-checksum " , " s " , pending_base_commitrev ) ;
variant_add_commit_details ( & dict , " pending-base- " , pending_base_commit ) ;
}
2015-09-27 19:44:57 +03:00
2017-01-27 07:31:53 +03:00
g_variant_dict_insert ( & dict , " origin " , " s " , refspec ) ;
2017-01-11 22:05:18 +03:00
if ( rpmostree_origin_get_packages ( origin ) ! = NULL )
g_variant_dict_insert ( & dict , " packages " , " ^as " , rpmostree_origin_get_packages ( origin ) ) ;
2015-09-08 17:31:22 +03:00
if ( sigs ! = NULL )
g_variant_dict_insert_value ( & dict , " signatures " , sigs ) ;
2016-07-21 23:28:20 +03:00
g_variant_dict_insert ( & dict , " gpg-enabled " , " b " , gpg_enabled ) ;
2015-09-08 17:31:22 +03:00
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 ) ) ) ;
2017-01-04 20:29:01 +03:00
g_variant_dict_insert ( & dict , " regenerate-initramfs " , " b " ,
rpmostree_origin_get_regenerate_initramfs ( origin ) ) ;
{ g_auto ( GStrv ) args = rpmostree_origin_get_initramfs_args ( origin ) ;
if ( args & & * args )
g_variant_dict_insert ( & dict , " initramfs-args " , " ^as " , args ) ;
}
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-07-18 19:54:28 +03:00
g_autofree gchar * head = NULL ;
2016-07-21 23:28:20 +03:00
gboolean gpg_enabled ;
2015-09-27 19:44:57 +03:00
const gchar * osname ;
GVariant * sigs = NULL ; /* floating variant */
GVariantDict dict ;
osname = ostree_deployment_get_osname ( deployment ) ;
if ( refspec )
origin_refspec = g_strdup ( refspec ) ;
else
2017-01-11 22:05:18 +03:00
{
g_autoptr ( RpmOstreeOrigin ) origin = NULL ;
2017-02-16 20:46:13 +03:00
origin = rpmostree_origin_parse_deployment ( deployment , error ) ;
2017-01-11 22:05:18 +03:00
if ( ! origin )
return NULL ;
origin_refspec = g_strdup ( rpmostree_origin_get_refspec ( origin ) ) ;
}
2015-09-27 19:44:57 +03:00
2016-07-18 18:36:50 +03:00
g_assert ( origin_refspec ) ;
2015-09-27 19:44:57 +03:00
2016-07-18 19:54:28 +03:00
/* allow_noent=TRUE since the ref may have been deleted for a
* rebase .
*/
if ( ! ostree_repo_resolve_rev ( repo , origin_refspec ,
TRUE , & head , error ) )
return NULL ;
if ( head = = NULL )
head = g_strdup ( ostree_deployment_get_csum ( deployment ) ) ;
2016-06-27 19:25:57 +03:00
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
2016-07-21 23:28:20 +03:00
sigs = rpmostreed_deployment_gpg_results ( repo , origin_refspec , head , & gpg_enabled ) ;
2015-09-27 19:44:57 +03:00
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 ) ;
2017-01-27 07:31:53 +03:00
variant_add_commit_details ( & dict , NULL , 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 ) ;
2016-07-21 23:28:20 +03:00
g_variant_dict_insert ( & dict , " gpg-enabled " , " b " , gpg_enabled ) ;
2016-07-18 18:36:50 +03:00
return g_variant_dict_end ( & dict ) ;
2015-09-27 19:44:57 +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 ;
}