2014-06-11 21:47:10 +04:00
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
2014-06-12 18:32:21 +04:00
* Copyright ( C ) 2014 Anne LoVerso < anne . loverso @ students . olin . edu >
2016-05-31 20:12:36 +03:00
* Copyright ( C ) 2016 Red Hat , Inc .
2014-06-11 21:47:10 +04:00
*
* 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>
2016-06-01 20:17:20 +03:00
# include <stdio.h>
2014-06-11 21:47:10 +04:00
# include <glib-unix.h>
2016-06-14 15:34:07 +03:00
# include <gio/gunixoutputstream.h>
2016-06-09 23:00:24 +03:00
# include <json-glib/json-glib.h>
2017-12-15 20:01:46 +03:00
# include <libdnf/libdnf.h>
2014-06-11 21:47:10 +04:00
# include "rpmostree-builtins.h"
2018-01-10 23:58:47 +03:00
# include "rpmostree-libbuiltin.h"
2015-06-13 03:19:16 +03:00
# include "rpmostree-dbus-helpers.h"
2016-08-30 22:57:40 +03:00
# include "rpmostree-util.h"
2018-01-16 19:13:44 +03:00
# include "rpmostree-core.h"
2017-07-04 20:50:52 +03:00
# include "rpmostree-rpm-util.h"
2016-05-29 21:15:29 +03:00
# include "libsd-locale-util.h"
2017-12-15 20:01:46 +03:00
# include "libsd-time-util.h"
2014-06-11 21:47:10 +04:00
2015-06-13 03:19:16 +03:00
# include <libglnx.h>
2014-06-11 21:47:10 +04:00
2018-02-13 17:25:20 +03:00
# define RPMOSTREE_AUTOMATIC_TIMER_OBJPATH \
" /org/freedesktop/systemd1/unit/rpm_2dostreed_2dautomatic_2etimer "
2017-12-15 20:01:46 +03:00
# define RPMOSTREE_AUTOMATIC_SERVICE_OBJPATH \
" /org/freedesktop/systemd1/unit/rpm_2dostreed_2dautomatic_2eservice "
2014-06-13 21:16:43 +04:00
static gboolean opt_pretty ;
2017-04-21 04:51:35 +03:00
static gboolean opt_verbose ;
2016-06-09 23:00:24 +03:00
static gboolean opt_json ;
2017-12-20 23:50:46 +03:00
static const char * opt_jsonpath ;
2014-06-13 21:16:43 +04:00
static GOptionEntry option_entries [ ] = {
2017-10-16 06:11:05 +03:00
{ " pretty " , ' p ' , G_OPTION_FLAG_HIDDEN , G_OPTION_ARG_NONE , & opt_pretty , " This option is deprecated and no longer has any effect " , NULL } ,
2017-04-21 04:51:35 +03:00
{ " verbose " , ' v ' , 0 , G_OPTION_ARG_NONE , & opt_verbose , " Print additional fields (e.g. StateRoot) " , NULL } ,
2016-06-09 23:00:24 +03:00
{ " json " , 0 , 0 , G_OPTION_ARG_NONE , & opt_json , " Output JSON " , NULL } ,
2017-12-20 23:50:46 +03:00
{ " jsonpath " , ' J ' , 0 , G_OPTION_ARG_STRING , & opt_jsonpath , " Filter JSONPath expression " , " EXPRESSION " } ,
2014-06-13 21:16:43 +04:00
{ NULL }
} ;
2017-12-15 23:00:41 +03:00
/* return space available for printing value side of kv */
static guint
get_textarea_width ( guint maxkeylen )
{
const guint columns = glnx_console_columns ( ) ;
/* +2 for initial leading spaces */
const guint right_side_width = maxkeylen + 2 + strlen ( " : " ) ;
if ( right_side_width > = columns )
return G_MAXUINT ; /* can't even print keys without wrapping, nothing pretty to do here */
/* the sha is already 64 chars, so no point in trying to use less */
return MAX ( OSTREE_SHA256_STRING_LEN , columns - right_side_width ) ;
2017-06-23 20:56:39 +03:00
}
2016-06-14 16:41:36 +03:00
static GVariant *
get_active_txn ( RPMOSTreeSysroot * sysroot_proxy )
{
GVariant * txn = rpmostree_sysroot_get_active_transaction ( sysroot_proxy ) ;
const char * a , * b , * c ;
if ( txn )
2016-10-28 22:54:12 +03:00
{
g_variant_get ( txn , " (&s&s&s) " , & a , & b , & c ) ;
if ( * a )
return txn ;
}
2016-06-14 16:41:36 +03:00
return NULL ;
}
2017-02-24 17:44:40 +03:00
static void
print_packages ( const char * k , guint max_key_len ,
const char * const * pkgs ,
const char * const * omit_pkgs )
{
2017-12-15 23:00:41 +03:00
g_autoptr ( GPtrArray ) packages_sorted = g_ptr_array_new_with_free_func ( g_free ) ;
2017-02-24 17:44:40 +03:00
static gsize regex_initialized ;
static GRegex * safe_chars_regex ;
if ( g_once_init_enter ( & regex_initialized ) )
{
safe_chars_regex = g_regex_new ( " ^[[:alnum:]-._]+$ " , 0 , 0 , NULL ) ;
g_assert ( safe_chars_regex ) ;
g_once_init_leave ( & regex_initialized , 1 ) ;
}
for ( char * * iter = ( char * * ) pkgs ; iter & & * iter ; iter + + )
{
if ( omit_pkgs ! = NULL & & g_strv_contains ( omit_pkgs , * iter ) )
continue ;
/* don't quote if it just has common pkgname/shell-safe chars */
if ( g_regex_match ( safe_chars_regex , * iter , 0 , 0 ) )
g_ptr_array_add ( packages_sorted , g_strdup ( * iter ) ) ;
else
g_ptr_array_add ( packages_sorted , g_shell_quote ( * iter ) ) ;
}
2017-12-15 23:00:41 +03:00
const guint n_packages = packages_sorted - > len ;
if ( n_packages = = 0 )
return ;
2018-01-11 00:03:10 +03:00
rpmostree_print_kv_no_newline ( k , max_key_len , " " ) ;
2017-12-15 23:00:41 +03:00
/* wrap pkglist output ourselves rather than letting the terminal cut us up */
const guint area_width = get_textarea_width ( max_key_len ) ;
guint current_width = 0 ;
for ( guint i = 0 ; i < n_packages ; i + + )
2017-02-24 17:44:40 +03:00
{
2017-12-15 23:00:41 +03:00
const char * pkg = packages_sorted - > pdata [ i ] ;
const guint pkg_width = strlen ( pkg ) ;
/* first print */
if ( current_width = = 0 )
{
g_print ( " %s " , pkg ) ;
current_width + = pkg_width ;
}
else if ( ( current_width + pkg_width + 1 ) < = area_width ) /* +1 for space separator */
{
g_print ( " %s " , pkg ) ;
current_width + = ( pkg_width + 1 ) ;
}
else
{
/* always print at least one per line, even if we overflow */
putc ( ' \n ' , stdout ) ;
2018-01-11 00:03:10 +03:00
rpmostree_print_kv_no_newline ( " " , max_key_len , pkg ) ;
2017-12-15 23:00:41 +03:00
current_width = pkg_width ;
}
2017-02-24 17:44:40 +03:00
}
2017-12-15 23:00:41 +03:00
putc ( ' \n ' , stdout ) ;
2017-02-24 17:44:40 +03:00
}
2017-03-03 23:48:56 +03:00
static const gchar * *
lookup_array_and_canonicalize ( GVariantDict * dict ,
const char * key )
{
g_autofree const gchar * * ret = NULL ;
if ( g_variant_dict_lookup ( dict , key , " ^a&s " , & ret ) )
{
/* Canonicalize length 0 strv to NULL */
if ( ! * ret )
g_clear_pointer ( & ret , g_free ) ;
}
return g_steal_pointer ( & ret ) ;
}
2017-09-21 05:11:37 +03:00
static void
gv_nevra_to_evr ( GString * buffer ,
GVariant * gv_nevra )
2017-07-04 20:50:52 +03:00
{
guint64 epoch ;
const char * version , * release ;
g_variant_get ( gv_nevra , " (sst&s&ss) " , NULL , NULL , & epoch , & version , & release , NULL ) ;
2017-09-21 05:11:37 +03:00
rpmostree_custom_nevra ( buffer , NULL , epoch , version , release , NULL ,
PKG_NEVRA_FLAGS_EPOCH_VERSION_RELEASE ) ;
2017-07-04 20:50:52 +03:00
}
2018-02-13 17:25:20 +03:00
typedef enum {
AUTO_UPDATE_SDSTATE_TIMER_UNKNOWN ,
AUTO_UPDATE_SDSTATE_TIMER_INACTIVE ,
AUTO_UPDATE_SDSTATE_SERVICE_FAILED ,
AUTO_UPDATE_SDSTATE_OK ,
} AutoUpdateSdState ;
2017-12-15 20:01:46 +03:00
static gboolean
2018-02-13 17:25:20 +03:00
get_last_auto_update_run ( GDBusConnection * connection ,
AutoUpdateSdState * out_state ,
char * * out_last_run ,
GCancellable * cancellable ,
GError * * error )
2017-12-15 20:01:46 +03:00
{
GLNX_AUTO_PREFIX_ERROR ( " Querying systemd for last auto-update run " , error ) ;
2018-02-13 17:25:20 +03:00
/* Check if the timer is running, otherwise systemd won't even keep timestamp info on dead
* services . Also good to tell users if the policy is not none , but timer is off ( though
* we don ' t print it as an error ; e . g . the timer might have been explicitly masked ) . */
g_autoptr ( GDBusProxy ) timer_unit_proxy =
2017-12-15 20:01:46 +03:00
g_dbus_proxy_new_sync ( connection , G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS , NULL ,
2018-02-13 17:25:20 +03:00
" org.freedesktop.systemd1 " , RPMOSTREE_AUTOMATIC_TIMER_OBJPATH ,
2017-12-15 20:01:46 +03:00
" org.freedesktop.systemd1.Unit " , cancellable , error ) ;
2018-02-13 17:25:20 +03:00
if ( ! timer_unit_proxy )
2017-12-15 20:01:46 +03:00
return FALSE ;
2018-02-13 17:25:20 +03:00
g_autoptr ( GVariant ) timer_state_val =
g_dbus_proxy_get_cached_property ( timer_unit_proxy , " ActiveState " ) ;
2017-12-15 20:01:46 +03:00
/* let's not error out if we can't msg systemd (e.g. bad sepol); just mark as unknown */
2018-02-13 17:25:20 +03:00
if ( timer_state_val = = NULL )
{
* out_state = AUTO_UPDATE_SDSTATE_TIMER_UNKNOWN ;
return TRUE ; /* NB early return */
}
const char * timer_state = g_variant_get_string ( timer_state_val , NULL ) ;
if ( g_str_equal ( timer_state , " inactive " ) )
2017-12-15 20:01:46 +03:00
{
2018-02-13 17:25:20 +03:00
* out_state = AUTO_UPDATE_SDSTATE_TIMER_INACTIVE ;
2017-12-15 20:01:46 +03:00
return TRUE ; /* NB early return */
}
2018-02-13 17:25:20 +03:00
g_autoptr ( GDBusProxy ) service_unit_proxy =
g_dbus_proxy_new_sync ( connection , G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS , NULL ,
" org.freedesktop.systemd1 " , RPMOSTREE_AUTOMATIC_SERVICE_OBJPATH ,
" org.freedesktop.systemd1.Unit " , cancellable , error ) ;
if ( ! service_unit_proxy )
return FALSE ;
g_autoptr ( GVariant ) service_state_val =
g_dbus_proxy_get_cached_property ( service_unit_proxy , " ActiveState " ) ;
const char * service_state = g_variant_get_string ( service_state_val , NULL ) ;
if ( g_str_equal ( service_state , " failed " ) )
2017-12-15 20:01:46 +03:00
{
2018-02-13 17:25:20 +03:00
* out_state = AUTO_UPDATE_SDSTATE_SERVICE_FAILED ;
2017-12-15 20:01:46 +03:00
return TRUE ; /* NB early return */
}
g_autoptr ( GDBusProxy ) service_proxy =
g_dbus_proxy_new_sync ( connection , G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS , NULL ,
" org.freedesktop.systemd1 " , RPMOSTREE_AUTOMATIC_SERVICE_OBJPATH ,
" org.freedesktop.systemd1.Service " , cancellable , error ) ;
if ( ! service_proxy )
return FALSE ;
g_autoptr ( GVariant ) t_val =
g_dbus_proxy_get_cached_property ( service_proxy , " ExecMainExitTimestamp " ) ;
g_autofree char * last_run = NULL ;
if ( t_val )
{
guint64 t = g_variant_get_uint64 ( t_val ) ;
if ( t > 0 )
{
char time_rel [ FORMAT_TIMESTAMP_RELATIVE_MAX ] = " " ;
libsd_format_timestamp_relative ( time_rel , sizeof ( time_rel ) , t ) ;
last_run = g_strdup ( time_rel ) ;
}
}
2018-02-13 17:25:20 +03:00
* out_state = AUTO_UPDATE_SDSTATE_OK ;
2017-12-15 20:01:46 +03:00
* out_last_run = g_steal_pointer ( & last_run ) ;
return TRUE ;
}
2018-01-17 23:25:43 +03:00
static gboolean
print_daemon_state ( RPMOSTreeSysroot * sysroot_proxy ,
2017-12-15 20:01:46 +03:00
GBusType bus_type ,
2018-01-17 23:25:43 +03:00
GCancellable * cancellable ,
GError * * error )
{
glnx_unref_object RPMOSTreeTransaction * txn_proxy = NULL ;
if ( ! rpmostree_transaction_connect_active ( sysroot_proxy , NULL , & txn_proxy ,
cancellable , error ) )
return FALSE ;
2017-12-15 20:01:46 +03:00
const char * policy = rpmostree_sysroot_get_automatic_update_policy ( sysroot_proxy ) ;
2018-01-17 23:25:43 +03:00
g_print ( " State: %s " , txn_proxy ? " busy " : " idle " ) ;
2017-12-15 20:01:46 +03:00
if ( g_str_equal ( policy , " none " ) )
g_print ( " ; auto updates disabled \n " ) ;
else
{
g_print ( " ; auto updates enabled " ) ;
/* don't try to get info from systemd if we're not on the system bus */
if ( bus_type ! = G_BUS_TYPE_SYSTEM )
g_print ( " (%s) \n " , policy ) ;
else
{
2018-02-13 17:25:20 +03:00
AutoUpdateSdState state ;
2017-12-15 20:01:46 +03:00
g_autofree char * last_run = NULL ;
GDBusConnection * connection =
g_dbus_proxy_get_connection ( G_DBUS_PROXY ( sysroot_proxy ) ) ;
2018-02-13 17:25:20 +03:00
if ( ! get_last_auto_update_run ( connection , & state , & last_run , cancellable , error ) )
2017-12-15 20:01:46 +03:00
return FALSE ;
2018-02-13 17:25:20 +03:00
switch ( state )
{
case AUTO_UPDATE_SDSTATE_TIMER_UNKNOWN :
{
g_print ( " (%s; unknown timer state) \n " , policy ) ;
break ;
}
case AUTO_UPDATE_SDSTATE_TIMER_INACTIVE :
{
g_print ( " (%s; timer inactive) \n " , policy ) ;
break ;
}
case AUTO_UPDATE_SDSTATE_SERVICE_FAILED :
{
g_print ( " (%s; %s%slast run failed%s%s) \n " , policy ,
get_red_start ( ) , get_bold_start ( ) ,
get_bold_end ( ) , get_red_end ( ) ) ;
break ;
}
case AUTO_UPDATE_SDSTATE_OK :
{
if ( last_run )
2018-02-14 17:27:06 +03:00
/* e.g. "last run 4h 32min ago" */
2018-02-13 17:25:20 +03:00
g_print ( " (%s; last run %s) \n " , policy , last_run ) ;
else
g_print ( " (%s; no runs since boot) \n " , policy ) ;
break ;
}
default :
{
g_assert_not_reached ( ) ;
}
}
2017-12-15 20:01:46 +03:00
}
}
2018-01-17 23:25:43 +03:00
if ( txn_proxy )
{
const char * title = rpmostree_transaction_get_title ( txn_proxy ) ;
g_print ( " Transaction: %s \n " , title ) ;
}
return TRUE ;
}
2016-05-31 20:12:36 +03:00
/* We will have an optimized path for the case where there are just
* two deployments , this code will be the generic fallback .
*/
static gboolean
2018-01-17 23:25:43 +03:00
print_deployments ( RPMOSTreeSysroot * sysroot_proxy ,
GVariant * deployments ,
GCancellable * cancellable ,
GError * * error )
2014-06-11 21:47:10 +04:00
{
2015-09-08 17:31:22 +03:00
GVariantIter iter ;
2016-06-14 16:41:36 +03:00
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
/* First, gather global state */
gboolean have_any_live_overlay = FALSE ;
g_variant_iter_init ( & iter , deployments ) ;
while ( TRUE )
{
g_autoptr ( GVariant ) child = g_variant_iter_next_value ( & iter ) ;
if ( ! child )
break ;
g_autoptr ( GVariantDict ) dict = g_variant_dict_new ( child ) ;
const gchar * live_inprogress ;
if ( ! g_variant_dict_lookup ( dict , " live-inprogress " , " &s " , & live_inprogress ) )
live_inprogress = NULL ;
const gchar * live_replaced ;
if ( ! g_variant_dict_lookup ( dict , " live-replaced " , " &s " , & live_replaced ) )
live_replaced = NULL ;
const gboolean have_live_changes = live_inprogress | | live_replaced ;
have_any_live_overlay = have_any_live_overlay | | have_live_changes ;
}
2016-06-14 16:41:36 +03:00
g_print ( " Deployments: \n " ) ;
2014-06-13 21:16:43 +04:00
2015-09-08 17:31:22 +03:00
g_variant_iter_init ( & iter , deployments ) ;
2018-01-17 23:25:43 +03:00
gboolean first = TRUE ;
2016-06-01 20:17:20 +03:00
while ( TRUE )
2014-06-11 21:47:10 +04:00
{
2016-06-01 20:17:20 +03:00
g_autoptr ( GVariant ) child = g_variant_iter_next_value ( & iter ) ;
g_autoptr ( GVariantDict ) dict = NULL ;
2017-10-19 22:31:50 +03:00
g_autoptr ( GVariantDict ) commit_meta_dict = NULL ;
g_autoptr ( GVariantDict ) layered_commit_meta_dict = NULL ;
2017-02-24 17:44:40 +03:00
gboolean is_locally_assembled = FALSE ;
g_autofree const gchar * * origin_packages = NULL ;
g_autofree const gchar * * origin_requested_packages = NULL ;
2017-03-03 23:48:56 +03:00
g_autofree const gchar * * origin_requested_local_packages = NULL ;
2017-07-04 20:50:52 +03:00
g_autoptr ( GVariant ) origin_base_removals = NULL ;
2017-06-20 19:21:57 +03:00
g_autofree const gchar * * origin_requested_base_removals = NULL ;
2017-07-04 20:50:52 +03:00
g_autoptr ( GVariant ) origin_base_local_replacements = NULL ;
g_autofree const gchar * * origin_requested_base_local_replacements = NULL ;
2016-06-01 20:17:20 +03:00
const gchar * origin_refspec ;
const gchar * id ;
const gchar * os_name ;
const gchar * checksum ;
const gchar * version_string ;
2016-06-01 20:53:49 +03:00
const gchar * unlocked ;
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
const gchar * live_inprogress ;
const gchar * live_replaced ;
2016-07-21 23:28:20 +03:00
gboolean gpg_enabled ;
2017-01-04 20:29:01 +03:00
gboolean regenerate_initramfs ;
2016-06-01 20:17:20 +03:00
guint64 t = 0 ;
int serial ;
gboolean is_booted ;
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
/* Add the long keys here */
2017-07-04 20:50:52 +03:00
const guint max_key_len = MAX ( strlen ( " InactiveBaseReplacements " ) ,
2017-06-05 19:37:56 +03:00
strlen ( " InterruptedLiveCommit " ) ) ;
2016-06-01 20:17:20 +03:00
g_autoptr ( GVariant ) signatures = NULL ;
g_autofree char * timestamp_string = NULL ;
2015-09-08 17:31:22 +03:00
2016-06-01 20:17:20 +03:00
if ( child = = NULL )
break ;
2017-03-03 23:48:56 +03:00
dict = g_variant_dict_new ( child ) ;
2016-06-01 20:17:20 +03:00
/* osname should always be present. */
g_assert ( g_variant_dict_lookup ( dict , " osname " , " &s " , & os_name ) ) ;
g_assert ( g_variant_dict_lookup ( dict , " id " , " &s " , & id ) ) ;
g_assert ( g_variant_dict_lookup ( dict , " serial " , " i " , & serial ) ) ;
2016-12-05 23:21:32 +03:00
g_assert ( g_variant_dict_lookup ( dict , " checksum " , " &s " , & checksum ) ) ;
2017-02-24 17:44:40 +03:00
2016-12-05 23:21:32 +03:00
if ( g_variant_dict_lookup ( dict , " origin " , " &s " , & origin_refspec ) )
2014-06-12 18:32:21 +04:00
{
2017-03-03 23:48:56 +03:00
origin_packages =
lookup_array_and_canonicalize ( dict , " packages " ) ;
origin_requested_packages =
lookup_array_and_canonicalize ( dict , " requested-packages " ) ;
origin_requested_local_packages =
lookup_array_and_canonicalize ( dict , " requested-local-packages " ) ;
2017-06-20 19:21:57 +03:00
origin_base_removals =
2017-07-04 20:50:52 +03:00
g_variant_dict_lookup_value ( dict , " base-removals " , G_VARIANT_TYPE ( " av " ) ) ;
2017-06-20 19:21:57 +03:00
origin_requested_base_removals =
lookup_array_and_canonicalize ( dict , " requested-base-removals " ) ;
2017-07-04 20:50:52 +03:00
origin_base_local_replacements =
g_variant_dict_lookup_value ( dict , " base-local-replacements " ,
G_VARIANT_TYPE ( " a(vv) " ) ) ;
origin_requested_base_local_replacements =
lookup_array_and_canonicalize ( dict , " requested-base-local-replacements " ) ;
2014-06-12 18:32:21 +04:00
}
2016-06-01 20:17:20 +03:00
else
origin_refspec = NULL ;
if ( ! g_variant_dict_lookup ( dict , " version " , " &s " , & version_string ) )
version_string = NULL ;
2016-06-01 20:53:49 +03:00
if ( ! g_variant_dict_lookup ( dict , " unlocked " , " &s " , & unlocked ) )
unlocked = NULL ;
2015-09-08 17:31:22 +03:00
2017-01-04 20:29:01 +03:00
if ( ! g_variant_dict_lookup ( dict , " regenerate-initramfs " , " b " , & regenerate_initramfs ) )
regenerate_initramfs = FALSE ;
2016-06-01 20:17:20 +03:00
signatures = g_variant_dict_lookup_value ( dict , " signatures " ,
G_VARIANT_TYPE ( " av " ) ) ;
2015-09-08 17:31:22 +03:00
2016-06-01 20:17:20 +03:00
if ( first )
first = FALSE ;
else
g_print ( " \n " ) ;
2015-07-16 21:11:35 +03:00
2016-06-25 00:40:46 +03:00
if ( ! g_variant_dict_lookup ( dict , " booted " , " b " , & is_booted ) )
is_booted = FALSE ;
2015-06-13 03:19:16 +03:00
2016-06-01 20:17:20 +03:00
g_print ( " %s " , is_booted ? libsd_special_glyph ( BLACK_CIRCLE ) : " " ) ;
2015-09-08 17:31:22 +03:00
2018-01-16 19:13:44 +03:00
RpmOstreeRefspecType refspectype = RPMOSTREE_REFSPEC_TYPE_OSTREE ;
2016-06-01 20:17:20 +03:00
if ( origin_refspec )
2018-01-16 19:13:44 +03:00
{
const char * refspec_data ;
if ( ! rpmostree_refspec_classify ( origin_refspec , & refspectype , & refspec_data , error ) )
return FALSE ;
g_autofree char * canonrefspec = rpmostree_refspec_to_string ( refspectype , refspec_data ) ;
g_print ( " %s " , canonrefspec ) ;
}
2016-06-01 20:17:20 +03:00
else
g_print ( " %s " , checksum ) ;
g_print ( " \n " ) ;
2017-02-24 17:44:40 +03:00
2017-03-21 19:48:09 +03:00
const char * base_checksum = NULL ;
g_variant_dict_lookup ( dict , " base-checksum " , " &s " , & base_checksum ) ;
if ( base_checksum ! = NULL )
is_locally_assembled = TRUE ;
2017-10-19 22:31:50 +03:00
/* Load the commit metadata into a dict */
{ g_autoptr ( GVariant ) commit_meta_v = NULL ;
g_assert ( g_variant_dict_lookup ( dict , " base-commit-meta " , " @a{sv} " , & commit_meta_v ) ) ;
commit_meta_dict = g_variant_dict_new ( commit_meta_v ) ;
}
if ( is_locally_assembled )
{
g_autoptr ( GVariant ) layered_commit_meta_v = NULL ;
g_assert ( g_variant_dict_lookup ( dict , " layered-commit-meta " , " @a{sv} " , & layered_commit_meta_v ) ) ;
layered_commit_meta_dict = g_variant_dict_new ( layered_commit_meta_v ) ;
}
const gchar * source_title = NULL ;
g_variant_dict_lookup ( commit_meta_dict , OSTREE_COMMIT_META_KEY_SOURCE_TITLE , " &s " , & source_title ) ;
if ( source_title )
g_print ( " %s %s \n " , libsd_special_glyph ( TREE_RIGHT ) , source_title ) ;
2017-03-21 19:48:09 +03:00
if ( is_locally_assembled )
g_assert ( g_variant_dict_lookup ( dict , " base-timestamp " , " t " , & t ) ) ;
else
g_assert ( g_variant_dict_lookup ( dict , " timestamp " , " t " , & t ) ) ;
2018-01-11 00:03:10 +03:00
timestamp_string = rpmostree_timestamp_str_from_unix_utc ( t ) ;
2017-03-21 19:48:09 +03:00
2018-01-11 00:03:10 +03:00
rpmostree_print_timestamp_version ( version_string , timestamp_string , max_key_len ) ;
2017-02-24 17:44:40 +03:00
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
if ( ! g_variant_dict_lookup ( dict , " live-inprogress " , " &s " , & live_inprogress ) )
live_inprogress = NULL ;
if ( ! g_variant_dict_lookup ( dict , " live-replaced " , " &s " , & live_replaced ) )
live_replaced = NULL ;
const gboolean have_live_changes = live_inprogress | | live_replaced ;
2017-03-21 19:48:09 +03:00
if ( is_locally_assembled )
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
{
if ( have_live_changes )
2018-01-11 00:03:10 +03:00
rpmostree_print_kv ( " BootedBaseCommit " , max_key_len , base_checksum ) ;
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
else
2018-01-11 00:03:10 +03:00
rpmostree_print_kv ( " BaseCommit " , max_key_len , base_checksum ) ;
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
if ( opt_verbose | | have_any_live_overlay )
2018-01-11 00:03:10 +03:00
rpmostree_print_kv ( " Commit " , max_key_len , checksum ) ;
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
}
else
{
if ( have_live_changes )
2018-01-11 00:03:10 +03:00
rpmostree_print_kv ( " BootedCommit " , max_key_len , checksum ) ;
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
if ( ! have_live_changes | | opt_verbose )
2018-01-11 00:03:10 +03:00
rpmostree_print_kv ( " Commit " , max_key_len , checksum ) ;
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
}
if ( live_inprogress )
{
if ( is_booted )
2018-01-10 23:58:47 +03:00
g_print ( " %s%s " , get_red_start ( ) , get_bold_start ( ) ) ;
2018-01-11 00:03:10 +03:00
rpmostree_print_kv ( " InterruptedLiveCommit " , max_key_len , live_inprogress ) ;
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
if ( is_booted )
2018-01-10 23:58:47 +03:00
g_print ( " %s%s " , get_bold_end ( ) , get_red_end ( ) ) ;
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
}
if ( live_replaced )
{
if ( is_booted )
2018-01-10 23:58:47 +03:00
g_print ( " %s%s " , get_red_start ( ) , get_bold_start ( ) ) ;
2018-01-11 00:03:10 +03:00
rpmostree_print_kv ( " LiveCommit " , max_key_len , live_replaced ) ;
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
if ( is_booted )
2018-01-10 23:58:47 +03:00
g_print ( " %s%s " , get_bold_end ( ) , get_red_end ( ) ) ;
Introduce `ex livefs`
There are a few different use cases here. First, for layering new packages,
there's no good reason for us to force a reboot. Second, we want some support
for cherry-picking security updates and allowing admins to restart services. Finally,
at some point we should offer support for entirely replacing the running tree
if that's what the user wants.
Until now we've been very conservative, but there's a spectrum here. In
particular, this patch changes things so we push a rollback before we start
doing anything live. I think in practice, many use cases would be totally fine
with doing most changes live, and falling back to the rollback if something went
wrong.
This initial code drop *only* supports live layering of new packages. However,
a lot of the base infrastructure is laid for future work.
For now, this will be classified as an experimental feature, hence `ex livefs`.
Part of: https://github.com/projectatomic/rpm-ostree/issues/639
Closes: #652
Approved by: jlebon
2017-03-01 01:16:48 +03:00
}
2017-01-27 07:31:53 +03:00
2017-04-14 17:44:58 +03:00
/* This used to be OSName; see https://github.com/ostreedev/ostree/pull/794 */
2017-04-21 04:51:35 +03:00
if ( opt_verbose )
2018-01-11 00:03:10 +03:00
rpmostree_print_kv ( " StateRoot " , max_key_len , os_name ) ;
2014-06-12 18:32:21 +04:00
2016-07-21 23:28:20 +03:00
if ( ! g_variant_dict_lookup ( dict , " gpg-enabled " , " b " , & gpg_enabled ) )
gpg_enabled = FALSE ;
if ( gpg_enabled )
2018-01-11 00:03:10 +03:00
rpmostree_print_gpg_info ( signatures , opt_verbose , max_key_len ) ;
2014-06-11 21:47:10 +04:00
2017-06-05 19:37:56 +03:00
/* print base overrides before overlays */
2017-07-04 20:50:52 +03:00
g_autoptr ( GPtrArray ) active_removals = g_ptr_array_new_with_free_func ( g_free ) ;
2017-06-20 19:21:57 +03:00
if ( origin_base_removals )
2017-07-04 20:50:52 +03:00
{
g_autoptr ( GString ) str = g_string_new ( " " ) ;
const guint n = g_variant_n_children ( origin_base_removals ) ;
for ( guint i = 0 ; i < n ; i + + )
{
g_autoptr ( GVariant ) gv_nevra ;
g_variant_get_child ( origin_base_removals , i , " v " , & gv_nevra ) ;
const char * name , * nevra ;
g_variant_get_child ( gv_nevra , 0 , " &s " , & nevra ) ;
g_variant_get_child ( gv_nevra , 1 , " &s " , & name ) ;
if ( str - > len )
g_string_append ( str , " , " ) ;
g_string_append ( str , nevra ) ;
g_ptr_array_add ( active_removals , g_strdup ( name ) ) ;
}
g_ptr_array_add ( active_removals , NULL ) ;
if ( str - > len )
2018-01-11 00:03:10 +03:00
rpmostree_print_kv ( " RemovedBasePackages " , max_key_len , str - > str ) ;
2017-07-04 20:50:52 +03:00
}
2017-06-20 19:21:57 +03:00
/* only print inactive base removal requests in verbose mode */
if ( origin_requested_base_removals & & opt_verbose )
print_packages ( " InactiveBaseRemovals " , max_key_len ,
2017-07-04 20:50:52 +03:00
origin_requested_base_removals ,
( const char * const * ) active_removals - > pdata ) ;
g_autoptr ( GPtrArray ) active_replacements = g_ptr_array_new_with_free_func ( g_free ) ;
if ( origin_base_local_replacements )
{
g_autoptr ( GString ) str = g_string_new ( " " ) ;
2017-09-21 05:11:37 +03:00
g_autoptr ( GHashTable ) grouped_diffs =
g_hash_table_new_full ( g_str_hash , g_str_equal , g_free ,
( GDestroyNotify ) g_ptr_array_unref ) ;
2017-07-04 20:50:52 +03:00
const guint n = g_variant_n_children ( origin_base_local_replacements ) ;
for ( guint i = 0 ; i < n ; i + + )
{
g_autoptr ( GVariant ) gv_nevra_new ;
g_autoptr ( GVariant ) gv_nevra_old ;
g_variant_get_child ( origin_base_local_replacements , i , " (vv) " ,
& gv_nevra_new , & gv_nevra_old ) ;
const char * nevra_new , * name_new , * name_old ;
g_variant_get_child ( gv_nevra_new , 0 , " &s " , & nevra_new ) ;
g_variant_get_child ( gv_nevra_new , 1 , " &s " , & name_new ) ;
g_variant_get_child ( gv_nevra_old , 1 , " &s " , & name_old ) ;
/* if pkgnames match, print a nicer version like treediff */
if ( g_str_equal ( name_new , name_old ) )
{
2017-09-21 05:11:37 +03:00
/* let's just use str as a scratchpad to avoid excessive mallocs; the str
* needs to be stretched anyway for the final output */
gsize original_size = str - > len ;
gv_nevra_to_evr ( str , gv_nevra_old ) ;
g_string_append ( str , " -> " ) ;
gv_nevra_to_evr ( str , gv_nevra_new ) ;
const char * diff = str - > str + original_size ;
GPtrArray * pkgs = g_hash_table_lookup ( grouped_diffs , diff ) ;
if ( ! pkgs )
{
pkgs = g_ptr_array_new_with_free_func ( g_free ) ;
g_hash_table_insert ( grouped_diffs , g_strdup ( diff ) , pkgs ) ;
}
g_ptr_array_add ( pkgs , g_strdup ( name_new ) ) ;
g_string_truncate ( str , original_size ) ;
2017-07-04 20:50:52 +03:00
}
else
{
2017-09-21 05:11:37 +03:00
if ( str - > len )
g_string_append ( str , " , " ) ;
2017-07-04 20:50:52 +03:00
const char * nevra_old ;
g_variant_get_child ( gv_nevra_old , 0 , " &s " , & nevra_old ) ;
g_string_append_printf ( str , " %s -> %s " , nevra_old , nevra_new ) ;
}
g_ptr_array_add ( active_replacements , g_strdup ( nevra_new ) ) ;
}
2017-09-21 05:11:37 +03:00
GLNX_HASH_TABLE_FOREACH_KV ( grouped_diffs , const char * , diff , GPtrArray * , pkgs )
{
if ( str - > len )
g_string_append ( str , " , " ) ;
for ( guint i = 0 , n = pkgs - > len ; i < n ; i + + )
{
const char * pkgname = g_ptr_array_index ( pkgs , i ) ;
if ( i > 0 )
g_string_append_c ( str , ' ' ) ;
g_string_append ( str , pkgname ) ;
}
g_string_append_c ( str , ' ' ) ;
g_string_append ( str , diff ) ;
}
2017-07-04 20:50:52 +03:00
g_ptr_array_add ( active_replacements , NULL ) ;
2017-09-21 05:11:37 +03:00
2017-07-04 20:50:52 +03:00
if ( str - > len )
2018-01-11 00:03:10 +03:00
rpmostree_print_kv ( " ReplacedBasePackages " , max_key_len , str - > str ) ;
2017-07-04 20:50:52 +03:00
}
if ( origin_requested_base_local_replacements & & opt_verbose )
print_packages ( " InactiveBaseReplacements " , max_key_len ,
origin_requested_base_local_replacements ,
( const char * const * ) active_replacements - > pdata ) ;
2017-06-05 19:37:56 +03:00
2017-06-20 19:12:36 +03:00
/* only print inactive layering requests in verbose mode */
if ( origin_requested_packages & & opt_verbose )
/* requested-packages - packages = inactive (i.e. dormant requests) */
print_packages ( " InactiveRequests " , max_key_len ,
2017-02-24 17:44:40 +03:00
origin_requested_packages , origin_packages ) ;
2017-03-03 23:48:56 +03:00
2016-06-01 20:17:20 +03:00
if ( origin_packages )
2017-02-24 17:44:40 +03:00
print_packages ( " LayeredPackages " , max_key_len ,
origin_packages , NULL ) ;
2017-01-04 20:29:01 +03:00
2017-03-03 23:48:56 +03:00
if ( origin_requested_local_packages )
print_packages ( " LocalPackages " , max_key_len ,
origin_requested_local_packages , NULL ) ;
2017-01-04 20:29:01 +03:00
if ( regenerate_initramfs )
{
g_autoptr ( GString ) buf = g_string_new ( " " ) ;
g_autofree char * * initramfs_args = NULL ;
g_variant_dict_lookup ( dict , " initramfs-args " , " ^a&s " , & initramfs_args ) ;
for ( char * * iter = initramfs_args ; iter & & * iter ; iter + + )
{
g_string_append ( buf , * iter ) ;
g_string_append_c ( buf , ' ' ) ;
}
if ( buf - > len = = 0 )
g_string_append ( buf , " regenerate " ) ;
2018-01-11 00:03:10 +03:00
rpmostree_print_kv ( " Initramfs " , max_key_len , buf - > str ) ;
2017-01-04 20:29:01 +03:00
}
2016-06-01 20:53:49 +03:00
if ( unlocked & & g_strcmp0 ( unlocked , " none " ) ! = 0 )
{
2018-01-10 23:58:47 +03:00
g_print ( " %s%s " , get_red_start ( ) , get_bold_start ( ) ) ;
2018-01-11 00:03:10 +03:00
rpmostree_print_kv ( " Unlocked " , max_key_len , unlocked ) ;
2018-01-10 23:58:47 +03:00
g_print ( " %s%s " , get_bold_end ( ) , get_red_end ( ) ) ;
2016-06-01 20:53:49 +03:00
}
2017-07-26 00:49:10 +03:00
const char * end_of_life_string = NULL ;
/* look for endoflife attribute in the deployment */
g_variant_dict_lookup ( dict , " endoflife " , " &s " , & end_of_life_string ) ;
if ( end_of_life_string )
{
2018-01-10 23:58:47 +03:00
g_print ( " %s%s " , get_red_start ( ) , get_bold_start ( ) ) ;
2018-01-11 00:03:10 +03:00
rpmostree_print_kv ( " EndOfLife " , max_key_len , end_of_life_string ) ;
2018-01-10 23:58:47 +03:00
g_print ( " %s%s " , get_bold_end ( ) , get_red_end ( ) ) ;
2017-07-26 00:49:10 +03:00
}
2015-04-07 20:49:21 +03:00
}
2016-05-31 20:12:36 +03:00
return TRUE ;
}
2017-12-28 23:11:32 +03:00
gboolean
2016-05-31 20:12:36 +03:00
rpmostree_builtin_status ( int argc ,
char * * argv ,
2017-03-15 21:52:43 +03:00
RpmOstreeCommandInvocation * invocation ,
2016-05-31 20:12:36 +03:00
GCancellable * cancellable ,
GError * * error )
{
2017-08-12 01:59:47 +03:00
g_autoptr ( GOptionContext ) context = g_option_context_new ( " " ) ;
2016-05-31 20:12:36 +03:00
glnx_unref_object RPMOSTreeOS * os_proxy = NULL ;
glnx_unref_object RPMOSTreeSysroot * sysroot_proxy = NULL ;
2017-03-23 21:50:18 +03:00
_cleanup_peer_ GPid peer_pid = 0 ;
2015-06-13 03:19:16 +03:00
2017-12-15 20:01:46 +03:00
GBusType bus_type ;
2016-05-31 20:12:36 +03:00
if ( ! rpmostree_option_context_parse ( context ,
option_entries ,
& argc , & argv ,
2017-03-15 21:52:43 +03:00
invocation ,
2016-05-31 20:12:36 +03:00
cancellable ,
2017-03-31 16:07:29 +03:00
NULL , NULL ,
2016-05-31 20:12:36 +03:00
& sysroot_proxy ,
2017-12-15 20:01:46 +03:00
& peer_pid , & bus_type ,
2016-05-31 20:12:36 +03:00
error ) )
2017-12-28 23:11:32 +03:00
return FALSE ;
2016-05-31 20:12:36 +03:00
2017-12-20 23:50:46 +03:00
if ( opt_json & & opt_jsonpath )
{
g_set_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ,
" Cannot specify both --json and --jsonpath " ) ;
2017-12-28 23:11:32 +03:00
return FALSE ;
2017-12-20 23:50:46 +03:00
}
2018-01-17 23:25:43 +03:00
if ( ! rpmostree_load_os_proxy ( sysroot_proxy , NULL , cancellable , & os_proxy , error ) )
2017-12-28 23:11:32 +03:00
return FALSE ;
2016-05-31 20:12:36 +03:00
2018-01-17 23:25:43 +03:00
g_autoptr ( GVariant ) deployments = rpmostree_sysroot_dup_deployments ( sysroot_proxy ) ;
2017-12-15 20:01:46 +03:00
g_autoptr ( GVariant ) cached_update = NULL ;
if ( rpmostree_os_get_has_cached_update_rpm_diff ( os_proxy ) )
cached_update = rpmostree_os_dup_cached_update ( os_proxy ) ;
2016-05-31 20:12:36 +03:00
2017-12-20 23:50:46 +03:00
if ( opt_json | | opt_jsonpath )
2016-06-09 23:00:24 +03:00
{
2016-06-14 15:34:07 +03:00
glnx_unref_object JsonBuilder * builder = json_builder_new ( ) ;
json_builder_begin_object ( builder ) ;
2017-12-20 23:50:46 +03:00
2016-06-14 15:34:07 +03:00
json_builder_set_member_name ( builder , " deployments " ) ;
2017-12-20 23:50:46 +03:00
json_builder_add_value ( builder , json_gvariant_serialize ( deployments ) ) ;
2016-06-14 16:41:36 +03:00
json_builder_set_member_name ( builder , " transaction " ) ;
2017-12-20 23:50:46 +03:00
GVariant * txn = get_active_txn ( sysroot_proxy ) ;
JsonNode * txn_node =
txn ? json_gvariant_serialize ( txn ) : json_node_new ( JSON_NODE_NULL ) ;
2016-06-14 16:41:36 +03:00
json_builder_add_value ( builder , txn_node ) ;
2017-12-15 20:01:46 +03:00
json_builder_set_member_name ( builder , " cached-update " ) ;
JsonNode * cached_update_node ;
if ( cached_update )
cached_update_node = json_gvariant_serialize ( cached_update ) ;
else
cached_update_node = json_node_new ( JSON_NODE_NULL ) ;
json_builder_add_value ( builder , cached_update_node ) ;
2016-06-14 15:34:07 +03:00
json_builder_end_object ( builder ) ;
2017-12-20 23:50:46 +03:00
JsonNode * json_root = json_builder_get_root ( builder ) ;
glnx_unref_object JsonGenerator * generator = json_generator_new ( ) ;
if ( opt_json )
json_generator_set_root ( generator , json_root ) ;
else
{
JsonNode * result = json_path_query ( opt_jsonpath , json_root , error ) ;
if ( ! result )
{
g_prefix_error ( error , " While compiling jsonpath: " ) ;
2017-12-28 23:11:32 +03:00
return FALSE ;
2017-12-20 23:50:46 +03:00
}
json_generator_set_root ( generator , result ) ;
json_node_free ( result ) ;
}
2016-06-14 15:34:07 +03:00
json_node_free ( json_root ) ;
2016-09-23 21:31:09 +03:00
/* NB: watch out for the misleading API docs */
2017-12-20 23:50:46 +03:00
glnx_unref_object GOutputStream * stdout_gio = g_unix_output_stream_new ( 1 , FALSE ) ;
2016-09-23 21:31:09 +03:00
if ( json_generator_to_stream ( generator , stdout_gio , NULL , error ) < = 0
| | ( error ! = NULL & & * error ! = NULL ) )
2017-12-28 23:11:32 +03:00
return FALSE ;
2016-06-09 23:00:24 +03:00
}
else
{
2017-12-15 20:01:46 +03:00
if ( ! print_daemon_state ( sysroot_proxy , bus_type , cancellable , error ) )
2018-01-17 23:25:43 +03:00
return FALSE ;
if ( ! print_deployments ( sysroot_proxy , deployments , cancellable , error ) )
2017-12-28 23:11:32 +03:00
return FALSE ;
2017-12-15 20:01:46 +03:00
const char * policy = rpmostree_sysroot_get_automatic_update_policy ( sysroot_proxy ) ;
gboolean auto_updates_enabled = ( ! g_str_equal ( policy , " none " ) ) ;
if ( cached_update & & auto_updates_enabled )
{
g_print ( " \n " ) ;
if ( ! rpmostree_print_cached_update ( cached_update , opt_verbose ,
cancellable , error ) )
return FALSE ;
}
2016-06-09 23:00:24 +03:00
}
2016-05-31 20:12:36 +03:00
2017-12-28 23:11:32 +03:00
return TRUE ;
2014-06-11 21:47:10 +04:00
}