2016-01-26 22:40:51 +03:00
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright ( C ) 2015 , 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 .
*/
# include "config.h"
# include <string.h>
# include <glib-unix.h>
# include <gio/gunixoutputstream.h>
# include <rpm/rpmts.h>
# include <stdio.h>
# include <libglnx.h>
# include <rpm/rpmmacro.h>
# include "rpmostree-container-builtins.h"
# include "rpmostree-util.h"
2016-02-09 18:38:38 +03:00
# include "rpmostree-core.h"
2016-01-26 22:40:51 +03:00
# include "rpmostree-libbuiltin.h"
2017-10-10 18:10:48 +03:00
# include "rpmostree-postprocess.h"
2016-01-26 22:40:51 +03:00
# include "rpmostree-rpm-util.h"
# include "rpmostree-unpacker.h"
2016-11-06 02:48:32 +03:00
# include "libglnx.h"
2016-01-26 22:40:51 +03:00
static GOptionEntry init_option_entries [ ] = {
{ NULL }
} ;
2017-09-29 23:55:54 +03:00
static gboolean opt_cache_only ;
2016-01-26 22:40:51 +03:00
static GOptionEntry assemble_option_entries [ ] = {
2017-09-29 23:55:54 +03:00
{ " cache-only " , ' C ' , 0 , G_OPTION_ARG_NONE , & opt_cache_only , " Assume cache is present, do not attempt to update it " , NULL } ,
2016-01-26 22:40:51 +03:00
{ NULL }
} ;
typedef struct {
int userroot_dfd ;
int roots_dfd ;
OstreeRepo * repo ;
2016-02-09 21:13:28 +03:00
RpmOstreeContext * ctx ;
2016-01-26 22:40:51 +03:00
int rpmmd_dfd ;
} ROContainerContext ;
2017-08-15 22:55:14 +03:00
# define RO_CONTAINER_CONTEXT_INIT { .userroot_dfd = -1, .roots_dfd = -1, .rpmmd_dfd = -1 }
2016-01-26 22:40:51 +03:00
static gboolean
roc_context_init_core ( ROContainerContext * rocctx ,
GError * * error )
{
2017-08-17 16:37:33 +03:00
if ( ! glnx_opendirat ( AT_FDCWD , " . " , TRUE , & rocctx - > userroot_dfd , error ) )
2017-08-09 17:40:58 +03:00
return FALSE ;
2016-01-26 22:40:51 +03:00
2017-08-09 17:40:58 +03:00
return TRUE ;
2016-01-26 22:40:51 +03:00
}
static gboolean
roc_context_init ( ROContainerContext * rocctx ,
GError * * error )
{
if ( ! roc_context_init_core ( rocctx , error ) )
2017-08-09 17:40:58 +03:00
return FALSE ;
2016-01-26 22:40:51 +03:00
2017-08-17 16:37:33 +03:00
rocctx - > repo = ostree_repo_open_at ( rocctx - > userroot_dfd , " repo " , NULL , error ) ;
if ( ! rocctx - > repo )
2017-08-09 17:40:58 +03:00
return FALSE ;
2016-01-26 22:40:51 +03:00
2017-09-28 22:47:40 +03:00
OstreeRepoMode mode = ostree_repo_get_mode ( rocctx - > repo ) ;
if ( mode ! = OSTREE_REPO_MODE_BARE_USER_ONLY )
return glnx_throw ( error , " container repos are now required to be in bare-user-only mode " ) ;
2017-08-17 16:37:33 +03:00
if ( ! glnx_opendirat ( rocctx - > userroot_dfd , " roots " , TRUE , & rocctx - > roots_dfd , error ) )
2017-08-09 17:40:58 +03:00
return FALSE ;
2016-01-26 22:40:51 +03:00
if ( ! glnx_opendirat ( rocctx - > userroot_dfd , " cache/rpm-md " , FALSE , & rocctx - > rpmmd_dfd , error ) )
2017-08-09 17:40:58 +03:00
return FALSE ;
2016-01-26 22:40:51 +03:00
2017-08-09 17:40:58 +03:00
return TRUE ;
2016-01-26 22:40:51 +03:00
}
static gboolean
roc_context_prepare_for_root ( ROContainerContext * rocctx ,
2016-02-10 11:25:58 +03:00
RpmOstreeTreespec * treespec ,
GCancellable * cancellable ,
2016-01-26 22:40:51 +03:00
GError * * error )
{
2017-09-28 22:47:40 +03:00
rocctx - > ctx = rpmostree_context_new_tree ( rocctx - > userroot_dfd , rocctx - > repo ,
cancellable , error ) ;
2016-02-09 21:13:28 +03:00
if ( ! rocctx - > ctx )
2017-08-09 17:40:58 +03:00
return FALSE ;
2016-01-26 22:40:51 +03:00
Add releasever opt, avoid opening up host's rpmdb in treecompose
Closes: https://github.com/projectatomic/rpm-ostree/issues/546
Previously, we'd open up the host's rpmdb for both `compose tree`
and `ex container`. In the first case, because we require root, we'd
succeed. For `ex container`, we'd spew an error.
Fixing this was trickier than I thought. First because there was
*also* a libdnf bug here: https://github.com/rpm-software-management/libdnf/pull/307
Second, there's a compatibility hazard here for anyone using `.repo` files that
reference `$releasever`. This actually happened to me with `ex container` as I'd
just done a `ln -s /etc/yum.repos.d/fedora.repo rpmmd.repos.d`. I fixed
that first by doing a `sed -i -e 's,$releasever,26,' rpmmd.repos.d/*.repo`.
As far as I can see today, none of Fedora Atomic or CentOS AH rely on this. But
in order to enhance compatibility, let's add a "releasever" option. This makes
it easier again to reuse stock `.repo` files if we wanted to do so.
(Also, I realized we can just use `/usr/share/empty` as *the* canonical immutable
empty directory)
Closes: #875
Approved by: jlebon
2017-07-13 19:37:41 +03:00
if ( ! rpmostree_context_setup ( rocctx - > ctx , NULL , NULL , treespec , cancellable , error ) )
2017-08-09 17:40:58 +03:00
return FALSE ;
2016-01-26 22:40:51 +03:00
2017-08-09 17:40:58 +03:00
return TRUE ;
2016-01-26 22:40:51 +03:00
}
static void
roc_context_deinit ( ROContainerContext * rocctx )
{
2017-08-15 22:55:14 +03:00
if ( rocctx - > userroot_dfd ! = - 1 )
2016-01-26 22:40:51 +03:00
( void ) close ( rocctx - > userroot_dfd ) ;
g_clear_object ( & rocctx - > repo ) ;
2017-08-15 22:55:14 +03:00
if ( rocctx - > roots_dfd ! = - 1 )
2016-01-26 22:40:51 +03:00
( void ) close ( rocctx - > roots_dfd ) ;
2017-08-15 22:55:14 +03:00
if ( rocctx - > rpmmd_dfd ! = - 1 )
2016-01-26 22:40:51 +03:00
( void ) close ( rocctx - > rpmmd_dfd ) ;
2016-02-09 21:13:28 +03:00
g_clear_object ( & rocctx - > ctx ) ;
2016-01-26 22:40:51 +03:00
}
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC ( ROContainerContext , roc_context_deinit )
int
rpmostree_container_builtin_init ( int argc ,
char * * argv ,
2017-03-15 21:52:43 +03:00
RpmOstreeCommandInvocation * invocation ,
2016-01-26 22:40:51 +03:00
GCancellable * cancellable ,
GError * * error )
{
g_auto ( ROContainerContext ) rocctx_data = RO_CONTAINER_CONTEXT_INIT ;
ROContainerContext * rocctx = & rocctx_data ;
2016-12-05 23:20:23 +03:00
g_autoptr ( GOptionContext ) context = g_option_context_new ( " " ) ;
2017-08-09 17:40:58 +03:00
2016-01-26 22:40:51 +03:00
if ( ! rpmostree_option_context_parse ( context ,
init_option_entries ,
& argc , & argv ,
2017-03-15 21:52:43 +03:00
invocation ,
2016-01-26 22:40:51 +03:00
cancellable ,
2017-03-31 16:07:29 +03:00
NULL , NULL , NULL , NULL ,
2016-01-26 22:40:51 +03:00
error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
if ( ! roc_context_init_core ( rocctx , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
2017-08-09 17:40:58 +03:00
static const char * const directories [ ] = { " repo " , " rpmmd.repos.d " , " cache/rpm-md " , " roots " , " tmp " } ;
for ( guint i = 0 ; i < G_N_ELEMENTS ( directories ) ; i + + )
2016-01-26 22:40:51 +03:00
{
if ( ! glnx_shutil_mkdir_p_at ( rocctx - > userroot_dfd , directories [ i ] , 0755 , cancellable , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
}
2017-08-17 16:37:33 +03:00
rocctx - > repo = ostree_repo_create_at ( rocctx - > userroot_dfd , " repo " ,
2017-09-28 22:47:40 +03:00
OSTREE_REPO_MODE_BARE_USER_ONLY , NULL ,
2017-08-17 16:37:33 +03:00
cancellable , error ) ;
if ( ! rocctx - > repo )
return FALSE ;
2016-01-26 22:40:51 +03:00
2017-08-09 17:40:58 +03:00
return EXIT_SUCCESS ;
2016-01-26 22:40:51 +03:00
}
/*
* Like symlinkat ( ) but overwrites ( atomically ) an existing
* symlink .
*/
static gboolean
symlink_at_replace ( const char * oldpath ,
int parent_dfd ,
const char * newpath ,
GCancellable * cancellable ,
GError * * error )
{
/* Possibly in the future generate a temporary random name here,
* would need to move " generate a temporary name " code into
* libglnx or glib ?
*/
const char * temppath = glnx_strjoina ( newpath , " .tmp " ) ;
2017-08-09 17:40:58 +03:00
/* Clean up any stale temporary links */
2016-01-26 22:40:51 +03:00
( void ) unlinkat ( parent_dfd , temppath , 0 ) ;
2017-08-09 17:40:58 +03:00
/* Create the temp link */
if ( TEMP_FAILURE_RETRY ( symlinkat ( oldpath , parent_dfd , temppath ) ) < 0 )
return glnx_throw_errno_prefix ( error , " symlinkat(%s) " , temppath) ;
2016-01-26 22:40:51 +03:00
2017-08-09 17:40:58 +03:00
/* Rename it into place */
if ( ! glnx_renameat ( parent_dfd , temppath , parent_dfd , newpath , error ) )
return FALSE ;
2016-01-26 22:40:51 +03:00
2017-08-09 17:40:58 +03:00
return TRUE ;
2016-01-26 22:40:51 +03:00
}
2017-10-17 21:52:30 +03:00
/* Download and import rpms, then generate a rootfs, and commit it */
static gboolean
download_rpms_and_assemble_commit ( ROContainerContext * rocctx ,
char * * out_commit ,
GCancellable * cancellable ,
GError * * error )
{
/* --- Download as necessary --- */
if ( ! rpmostree_context_download ( rocctx - > ctx , cancellable , error ) )
return FALSE ;
/* --- Import as necessary --- */
if ( ! rpmostree_context_import ( rocctx - > ctx , cancellable , error ) )
return FALSE ;
2017-11-07 18:53:39 +03:00
if ( ! rpmostree_context_assemble ( rocctx - > ctx , cancellable , error ) )
2017-10-17 21:52:30 +03:00
return FALSE ;
2017-11-07 18:53:39 +03:00
if ( ! rpmostree_rootfs_postprocess_common ( rpmostree_context_get_tmprootfs_dfd ( rocctx - > ctx ) ,
cancellable , error ) )
2017-10-26 00:28:27 +03:00
return FALSE ;
2017-10-17 21:52:30 +03:00
g_autofree char * ret_commit = NULL ;
2017-11-07 18:53:39 +03:00
if ( ! rpmostree_context_commit ( rocctx - > ctx , NULL , RPMOSTREE_ASSEMBLE_TYPE_SERVER_BASE ,
& ret_commit , cancellable , error ) )
2017-10-17 21:52:30 +03:00
return FALSE ;
* out_commit = g_steal_pointer ( & ret_commit ) ;
return TRUE ;
}
2016-01-26 22:40:51 +03:00
int
rpmostree_container_builtin_assemble ( int argc ,
char * * argv ,
2017-03-15 21:52:43 +03:00
RpmOstreeCommandInvocation * invocation ,
2016-01-26 22:40:51 +03:00
GCancellable * cancellable ,
GError * * error )
{
2016-12-05 23:20:23 +03:00
g_autoptr ( GOptionContext ) context = g_option_context_new ( " NAME [PKGNAME PKGNAME...] " ) ;
2016-01-26 22:40:51 +03:00
g_auto ( ROContainerContext ) rocctx_data = RO_CONTAINER_CONTEXT_INIT ;
ROContainerContext * rocctx = & rocctx_data ;
2017-05-30 00:27:31 +03:00
2016-01-26 22:40:51 +03:00
if ( ! rpmostree_option_context_parse ( context ,
assemble_option_entries ,
& argc , & argv ,
2017-03-15 21:52:43 +03:00
invocation ,
2016-01-26 22:40:51 +03:00
cancellable ,
2017-03-31 16:07:29 +03:00
NULL , NULL , NULL , NULL ,
2016-01-26 22:40:51 +03:00
error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
if ( argc < 1 )
{
2016-02-10 11:25:58 +03:00
rpmostree_usage_error ( context , " SPEC must be specified " , error ) ;
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
}
2017-08-09 17:40:58 +03:00
const char * specpath = argv [ 1 ] ;
g_autoptr ( RpmOstreeTreespec ) treespec = rpmostree_treespec_new_from_path ( specpath , error ) ;
2016-02-10 11:25:58 +03:00
if ( ! treespec )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-02-10 11:25:58 +03:00
2017-08-09 17:40:58 +03:00
const char * name = rpmostree_treespec_get_ref ( treespec ) ;
2016-03-14 18:34:01 +03:00
if ( name = = NULL )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Missing ref in treespec " ) ;
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-03-14 18:34:01 +03:00
}
2016-01-26 22:40:51 +03:00
if ( ! roc_context_init ( rocctx , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
2017-08-09 17:40:58 +03:00
const char * target_rootdir = glnx_strjoina ( name , " .0 " ) ;
2016-01-26 22:40:51 +03:00
2017-10-17 23:17:25 +03:00
if ( ! glnx_fstatat_allow_noent ( rocctx - > roots_dfd , target_rootdir , NULL ,
2017-09-28 23:21:10 +03:00
AT_SYMLINK_NOFOLLOW , error ) )
2016-01-26 22:40:51 +03:00
{
2017-09-28 23:21:10 +03:00
glnx_set_error_from_errno ( error ) ;
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
}
2017-09-28 23:21:10 +03:00
if ( errno = = 0 )
2016-01-26 22:40:51 +03:00
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
" Tree %s already exists " , target_rootdir ) ;
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
}
2016-03-21 22:41:41 +03:00
if ( ! roc_context_prepare_for_root ( rocctx , treespec , cancellable , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
2017-09-29 23:55:54 +03:00
DnfContext * dnfctx = rpmostree_context_get_hif ( rocctx - > ctx ) ;
if ( opt_cache_only )
dnf_context_set_cache_age ( dnfctx , G_MAXUINT ) ;
2016-01-26 22:40:51 +03:00
/* --- Resolving dependencies --- */
2017-05-30 00:27:31 +03:00
if ( ! rpmostree_context_prepare ( rocctx - > ctx , cancellable , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
2016-07-24 21:26:21 +03:00
rpmostree_print_transaction ( rpmostree_context_get_hif ( rocctx - > ctx ) ) ;
2017-08-09 17:40:58 +03:00
g_autofree char * commit = NULL ;
2017-10-17 21:52:30 +03:00
if ( ! download_rpms_and_assemble_commit ( rocctx , & commit , cancellable , error ) )
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
g_print ( " Checking out %s @ %s... \n " , name , commit ) ;
2016-08-04 14:07:57 +03:00
{ OstreeRepoCheckoutAtOptions opts = { OSTREE_REPO_CHECKOUT_MODE_USER ,
OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES , } ;
2016-01-26 22:40:51 +03:00
/* Also, what we really want here is some sort of sane lifecycle
* management with whatever is running in the root .
*/
if ( ! glnx_shutil_rm_rf_at ( rocctx - > roots_dfd , target_rootdir , cancellable , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
2016-08-04 14:07:57 +03:00
if ( ! ostree_repo_checkout_at ( rocctx - > repo , & opts , rocctx - > roots_dfd , target_rootdir ,
commit , cancellable , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
}
g_print ( " Checking out %s @ %s...done \n " , name , commit ) ;
if ( ! symlink_at_replace ( target_rootdir , rocctx - > roots_dfd , name ,
cancellable , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
g_print ( " Creating current symlink...done \n " ) ;
2017-08-09 17:40:58 +03:00
return EXIT_SUCCESS ;
2016-01-26 22:40:51 +03:00
}
# define APP_VERSION_REGEXP ".+\\.([01])"
static gboolean
parse_app_version ( const char * name ,
guint * out_version ,
GError * * error )
{
2017-08-09 17:40:58 +03:00
g_autoptr ( GMatchInfo ) match = NULL ;
2016-01-26 22:40:51 +03:00
static gsize regex_initialized ;
static GRegex * regex ;
int ret_version ;
if ( g_once_init_enter ( & regex_initialized ) )
{
regex = g_regex_new ( APP_VERSION_REGEXP , 0 , 0 , NULL ) ;
g_assert ( regex ) ;
g_once_init_leave ( & regex_initialized , 1 ) ;
}
if ( ! g_regex_match ( regex , name , 0 , & match ) )
2017-08-09 17:40:58 +03:00
return glnx_throw ( error , " Invalid app link %s " , name ) ;
2016-01-26 22:40:51 +03:00
{ g_autofree char * version_str = g_match_info_fetch ( match , 1 ) ;
ret_version = g_ascii_strtoull ( version_str , NULL , 10 ) ;
2017-05-30 00:27:31 +03:00
2016-01-26 22:40:51 +03:00
switch ( ret_version )
{
case 0 :
case 1 :
break ;
default :
2017-08-09 17:40:58 +03:00
return glnx_throw ( error , " Invalid version in app link %s " , name ) ;
2016-01-26 22:40:51 +03:00
}
}
* out_version = ret_version ;
2017-08-09 17:40:58 +03:00
return TRUE ;
2016-01-26 22:40:51 +03:00
}
gboolean
2017-03-15 21:52:43 +03:00
rpmostree_container_builtin_upgrade ( int argc , char * * argv ,
RpmOstreeCommandInvocation * invocation ,
GCancellable * cancellable , GError * * error )
2016-01-26 22:40:51 +03:00
{
2016-12-05 23:20:23 +03:00
g_autoptr ( GOptionContext ) context = g_option_context_new ( " NAME " ) ;
2016-01-26 22:40:51 +03:00
g_auto ( ROContainerContext ) rocctx_data = RO_CONTAINER_CONTEXT_INIT ;
ROContainerContext * rocctx = & rocctx_data ;
2017-08-09 17:40:58 +03:00
2016-01-26 22:40:51 +03:00
if ( ! rpmostree_option_context_parse ( context ,
assemble_option_entries ,
& argc , & argv ,
2017-03-15 21:52:43 +03:00
invocation ,
2016-01-26 22:40:51 +03:00
cancellable ,
2017-03-31 16:07:29 +03:00
NULL , NULL , NULL , NULL ,
2016-01-26 22:40:51 +03:00
error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
if ( argc < 1 )
{
rpmostree_usage_error ( context , " NAME must be specified " , error ) ;
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
}
2017-08-09 17:40:58 +03:00
const char * name = argv [ 1 ] ;
2016-01-26 22:40:51 +03:00
if ( ! roc_context_init ( rocctx , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
2017-08-09 17:40:58 +03:00
g_autofree char * target_current_root = glnx_readlinkat_malloc ( rocctx - > roots_dfd , name , cancellable , error ) ;
2016-01-26 22:40:51 +03:00
if ( ! target_current_root )
{
g_prefix_error ( error , " Reading app link %s: " , name ) ;
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
}
2017-08-16 16:07:34 +03:00
guint current_version = 2 ;
2016-01-26 22:40:51 +03:00
if ( ! parse_app_version ( target_current_root , & current_version , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2017-08-16 16:07:34 +03:00
g_assert_cmpuint ( current_version , < , 2 ) ;
2016-01-26 22:40:51 +03:00
2017-08-09 17:40:58 +03:00
g_autofree char * commit_checksum = NULL ;
g_autofree char * previous_state_sha512 = NULL ;
g_autoptr ( GVariant ) metadata = NULL ;
g_autoptr ( RpmOstreeTreespec ) treespec = NULL ;
2016-01-26 22:40:51 +03:00
{ g_autoptr ( GVariantDict ) metadata_dict = NULL ;
2016-02-10 11:25:58 +03:00
g_autoptr ( GVariant ) spec_v = NULL ;
g_autoptr ( GVariant ) previous_sha512_v = NULL ;
2017-08-09 17:40:58 +03:00
g_autoptr ( GVariant ) commit = NULL ;
2016-01-26 22:40:51 +03:00
if ( ! ostree_repo_resolve_rev ( rocctx - > repo , name , FALSE , & commit_checksum , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
if ( ! ostree_repo_load_variant ( rocctx - > repo , OSTREE_OBJECT_TYPE_COMMIT , commit_checksum ,
& commit , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
metadata = g_variant_get_child_value ( commit , 0 ) ;
metadata_dict = g_variant_dict_new ( metadata ) ;
2016-02-10 11:25:58 +03:00
spec_v = _rpmostree_vardict_lookup_value_required ( metadata_dict , " rpmostree.spec " ,
( GVariantType * ) " a{sv} " , error ) ;
if ( ! spec_v )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
2016-02-10 11:25:58 +03:00
treespec = rpmostree_treespec_new ( spec_v ) ;
2016-01-26 22:40:51 +03:00
2016-02-10 11:25:58 +03:00
previous_sha512_v = _rpmostree_vardict_lookup_value_required ( metadata_dict ,
" rpmostree.state-sha512 " ,
( GVariantType * ) " s " , error ) ;
if ( ! previous_sha512_v )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
2016-02-10 11:25:58 +03:00
previous_state_sha512 = g_variant_dup_string ( previous_sha512_v , NULL ) ;
2016-01-26 22:40:51 +03:00
}
2016-02-10 11:25:58 +03:00
2017-08-16 16:07:34 +03:00
guint new_version = ( current_version = = 0 ? 1 : 0 ) ;
2017-08-09 17:40:58 +03:00
const char * target_new_root ;
2016-02-10 11:25:58 +03:00
if ( new_version = = 0 )
target_new_root = glnx_strjoina ( name , " .0 " ) ;
else
target_new_root = glnx_strjoina ( name , " .1 " ) ;
2016-03-21 22:41:41 +03:00
if ( ! roc_context_prepare_for_root ( rocctx , treespec , cancellable , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-02-10 11:25:58 +03:00
2017-05-30 00:27:31 +03:00
if ( ! rpmostree_context_prepare ( rocctx - > ctx , cancellable , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
2016-07-24 21:26:21 +03:00
rpmostree_print_transaction ( rpmostree_context_get_hif ( rocctx - > ctx ) ) ;
2017-10-13 16:22:15 +03:00
{
g_autofree char * new_state_sha512 = NULL ;
if ( ! rpmostree_context_get_state_sha512 ( rocctx - > ctx , & new_state_sha512 , error ) )
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
2016-02-10 11:25:58 +03:00
if ( strcmp ( new_state_sha512 , previous_state_sha512 ) = = 0 )
2016-01-26 22:40:51 +03:00
{
g_print ( " No changes in inputs to %s (%s) \n " , name , commit_checksum ) ;
2017-08-09 17:40:58 +03:00
/* Note early return */
return EXIT_SUCCESS ;
2016-01-26 22:40:51 +03:00
}
}
2017-08-09 17:40:58 +03:00
g_autofree char * new_commit_checksum = NULL ;
2017-10-17 21:52:30 +03:00
if ( ! download_rpms_and_assemble_commit ( rocctx , & new_commit_checksum , cancellable , error ) )
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
g_print ( " Checking out %s @ %s... \n " , name , new_commit_checksum ) ;
2016-08-04 14:07:57 +03:00
{ OstreeRepoCheckoutAtOptions opts = { OSTREE_REPO_CHECKOUT_MODE_USER ,
OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES , } ;
2016-01-26 22:40:51 +03:00
2016-08-04 14:07:57 +03:00
if ( ! ostree_repo_checkout_at ( rocctx - > repo , & opts , rocctx - > roots_dfd , target_new_root ,
new_commit_checksum , cancellable , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
}
g_print ( " Checking out %s @ %s...done \n " , name , new_commit_checksum ) ;
if ( ! symlink_at_replace ( target_new_root , rocctx - > roots_dfd , name ,
cancellable , error ) )
2017-08-09 17:40:58 +03:00
return EXIT_FAILURE ;
2016-01-26 22:40:51 +03:00
g_print ( " Creating current symlink...done \n " ) ;
2017-08-09 17:40:58 +03:00
return EXIT_SUCCESS ;
2016-01-26 22:40:51 +03:00
}