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>
2014-06-11 21:47:10 +04:00
# include "rpmostree-builtins.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"
2016-05-29 21:15:29 +03:00
# include "libsd-locale-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
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 ;
2014-06-13 21:16:43 +04:00
static GOptionEntry option_entries [ ] = {
2016-06-01 20:17:20 +03:00
{ " pretty " , ' p ' , 0 , 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 } ,
2014-06-13 21:16:43 +04:00
{ NULL }
} ;
2015-06-13 03:19:16 +03:00
static void
2016-06-01 20:17:20 +03:00
printpad ( char c , guint n )
2014-06-13 21:16:43 +04:00
{
2016-06-01 20:17:20 +03:00
for ( guint i = 0 ; i < n ; i + + )
putc ( c , stdout ) ;
2014-06-13 21:16:43 +04:00
}
2016-06-01 20:17:20 +03:00
static void
print_kv ( const char * key ,
guint maxkeylen ,
const char * value )
2015-02-11 21:06:43 +03:00
{
2016-06-01 20:17:20 +03:00
int pad = maxkeylen - strlen ( key ) ;
g_assert ( pad > = 0 ) ;
/* +2 for initial leading spaces */
printpad ( ' ' , pad + 2 ) ;
printf ( " %s: %s \n " , key , value ) ;
2015-02-11 21:06:43 +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 )
{
g_autofree char * packages_joined = NULL ;
g_autoptr ( GPtrArray ) packages_sorted =
g_ptr_array_new_with_free_func ( g_free ) ;
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 ) ) ;
}
if ( packages_sorted - > len > 0 )
{
g_ptr_array_sort ( packages_sorted , rpmostree_ptrarray_sort_compare_strings ) ;
g_ptr_array_add ( packages_sorted , NULL ) ;
packages_joined = g_strjoinv ( " " , ( char * * ) packages_sorted - > pdata ) ;
print_kv ( k , max_key_len , packages_joined ) ;
}
}
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 ) ;
}
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
2016-06-01 20:17:20 +03:00
status_generic ( RPMOSTreeSysroot * sysroot_proxy ,
RPMOSTreeOS * os_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-01 20:17:20 +03:00
gboolean first = TRUE ;
2016-06-01 20:53:49 +03:00
const int is_tty = isatty ( 1 ) ;
2016-06-09 22:47:05 +03:00
const char * bold_prefix = is_tty ? " \x1b [1m " : " " ;
const char * bold_suffix = is_tty ? " \x1b [0m " : " " ;
const char * red_prefix = is_tty ? " \x1b [31m " : " " ;
const char * red_suffix = is_tty ? " \x1b [22m " : " " ;
2016-06-14 16:41:36 +03:00
GVariant * txn = get_active_txn ( sysroot_proxy ) ;
2017-05-31 23:39:44 +03:00
const char * txn_path = rpmostree_sysroot_get_active_transaction_path ( sysroot_proxy ) ;
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 ;
}
2017-05-31 23:39:44 +03:00
if ( txn & & txn_path )
2016-06-14 16:41:36 +03:00
{
const char * method , * sender , * path ;
g_variant_get ( txn , " (&s&s&s) " , & method , & sender , & path ) ;
2017-05-31 23:39:44 +03:00
/* Things currently could race here if the transaction completes after we get the
* path . For now , just ignore errors . TODO : A more correct fix would involve a loop
* on watching the path property , trying a connection , and re - reading the value
* and only erroring out if the property hasn ' t changed .
*/
g_autoptr ( RPMOSTreeTransactionProxy ) txn_proxy = ( RPMOSTreeTransactionProxy * ) rpmostree_transaction_connect ( txn_path , NULL , NULL ) ;
if ( txn_proxy )
{
const char * title = rpmostree_transaction_get_title ( ( RPMOSTreeTransaction * ) txn_proxy ) ;
g_print ( " State: transaction: %s \n " , title ) ;
}
/* Print the address if verbose, *or* if we somehow failed to get
* the txn , so we aren ' t masking errors .
*/
if ( opt_verbose | | ( path & & ! txn_proxy ) )
g_print ( " TransactionAddress: %s %s %s \n " , method , sender , path ) ;
2016-06-14 16:41:36 +03:00
}
else
g_print ( " State: idle \n " ) ;
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 ) ;
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-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-06-05 19:37:56 +03:00
g_autofree const gchar * * origin_removed_base_packages = 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 ;
2017-01-27 07:31:53 +03:00
const gboolean was_first = first ;
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-06-05 19:37:56 +03:00
const guint max_key_len = MAX ( strlen ( " RemovedBasePackages " ) ,
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-05 19:37:56 +03:00
origin_removed_base_packages =
lookup_array_and_canonicalize ( dict , " removed-base-packages " ) ;
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
2016-06-01 20:17:20 +03:00
if ( origin_refspec )
g_print ( " %s " , origin_refspec ) ;
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 ;
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 ) ) ;
{ g_autoptr ( GDateTime ) timestamp = g_date_time_new_from_unix_utc ( t ) ;
if ( timestamp ! = NULL )
timestamp_string = g_date_time_format ( timestamp , " %Y-%m-%d %T " ) ;
else
timestamp_string = g_strdup_printf ( " (invalid timestamp) " ) ;
}
2016-06-01 20:17:20 +03:00
if ( version_string )
2015-02-11 21:06:43 +03:00
{
2016-06-09 22:47:05 +03:00
g_autofree char * version_time
= g_strdup_printf ( " %s%s%s (%s) " , bold_prefix , version_string ,
bold_suffix , timestamp_string ) ;
2016-06-01 20:17:20 +03:00
print_kv ( " Version " , max_key_len , version_time ) ;
2015-02-11 21:06:43 +03:00
}
else
{
2016-06-01 20:17:20 +03:00
print_kv ( " Timestamp " , max_key_len , timestamp_string ) ;
2015-02-11 21:06:43 +03:00
}
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 )
print_kv ( " BootedBaseCommit " , max_key_len , base_checksum ) ;
else
print_kv ( " BaseCommit " , max_key_len , base_checksum ) ;
if ( opt_verbose | | have_any_live_overlay )
print_kv ( " Commit " , max_key_len , checksum ) ;
}
else
{
if ( have_live_changes )
print_kv ( " BootedCommit " , max_key_len , checksum ) ;
if ( ! have_live_changes | | opt_verbose )
print_kv ( " Commit " , max_key_len , checksum ) ;
}
if ( live_inprogress )
{
if ( is_booted )
g_print ( " %s%s " , red_prefix , bold_prefix ) ;
print_kv ( " InterruptedLiveCommit " , max_key_len , live_inprogress ) ;
if ( is_booted )
g_print ( " %s%s " , bold_suffix , red_suffix ) ;
}
if ( live_replaced )
{
if ( is_booted )
g_print ( " %s%s " , red_prefix , bold_prefix ) ;
print_kv ( " LiveCommit " , max_key_len , live_replaced ) ;
if ( is_booted )
g_print ( " %s%s " , bold_suffix , red_suffix ) ;
}
2017-01-27 07:31:53 +03:00
/* Show any difference between the baseref vs head, but only for the
booted commit , and only if there isn ' t a pending deployment . Otherwise
it ' s either unnecessary or too noisy .
*/
if ( is_booted & & was_first )
{
const gchar * pending_checksum = NULL ;
const gchar * pending_version = NULL ;
if ( g_variant_dict_lookup ( dict , " pending-base-checksum " , " &s " , & pending_checksum ) )
{
print_kv ( is_locally_assembled ? " PendingBaseCommit " : " PendingCommit " ,
max_key_len , pending_checksum ) ;
g_assert ( g_variant_dict_lookup ( dict , " pending-base-timestamp " , " t " , & t ) ) ;
g_variant_dict_lookup ( dict , " pending-base-version " , " &s " , & pending_version ) ;
if ( pending_version )
{
g_autoptr ( GDateTime ) timestamp = g_date_time_new_from_unix_utc ( t ) ;
g_autofree char * version_time = NULL ;
if ( timestamp ! = NULL )
timestamp_string = g_date_time_format ( timestamp , " %Y-%m-%d %T " ) ;
else
timestamp_string = g_strdup_printf ( " (invalid timestamp) " ) ;
version_time = g_strdup_printf ( " %s (%s) " , pending_version , timestamp_string ) ;
print_kv ( is_locally_assembled ? " PendingBaseVersion " : " PendingVersion " ,
max_key_len , version_time ) ;
}
}
}
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 )
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 )
2014-06-13 21:16:43 +04:00
{
2016-07-21 23:28:20 +03:00
if ( signatures )
{
guint n_sigs = g_variant_n_children ( signatures ) ;
g_autofree char * gpgheader = g_strdup_printf ( " %u signature%s " , n_sigs ,
n_sigs = = 1 ? " " : " s " ) ;
const guint gpgpad = max_key_len + 4 ;
char gpgspaces [ gpgpad + 1 ] ;
memset ( gpgspaces , ' ' , gpgpad ) ;
gpgspaces [ gpgpad ] = ' \0 ' ;
print_kv ( " GPGSignature " , max_key_len , gpgheader ) ;
rpmostree_print_signatures ( signatures , gpgspaces ) ;
}
else
{
print_kv ( " GPGSignature " , max_key_len , " (unsigned) " ) ;
}
2014-06-13 21:16:43 +04:00
}
2014-06-11 21:47:10 +04:00
2017-06-05 19:37:56 +03:00
/* print base overrides before overlays */
if ( origin_removed_base_packages )
print_packages ( " RemovedBasePackages " , max_key_len ,
origin_removed_base_packages , NULL ) ;
2017-02-24 17:44:40 +03:00
/* let's be nice and only print requested - layered, rather than repeating
* the ones in layered twice */
if ( origin_requested_packages )
print_packages ( " RequestedPackages " , max_key_len ,
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 " ) ;
print_kv ( " Initramfs " , max_key_len , buf - > str ) ;
}
2016-06-01 20:53:49 +03:00
if ( unlocked & & g_strcmp0 ( unlocked , " none " ) ! = 0 )
{
2016-06-09 22:47:05 +03:00
g_print ( " %s%s " , red_prefix , bold_prefix ) ;
2016-06-01 20:53:49 +03:00
print_kv ( " Unlocked " , max_key_len , unlocked ) ;
2016-06-09 22:47:05 +03:00
g_print ( " %s%s " , bold_suffix , red_suffix ) ;
2016-06-01 20:53:49 +03:00
}
2015-04-07 20:49:21 +03:00
}
2016-05-31 20:12:36 +03:00
return TRUE ;
}
int
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 )
{
2016-12-05 23:20:23 +03:00
g_autoptr ( GOptionContext ) context = g_option_context_new ( " - Get the version of the booted system " ) ;
2016-05-31 20:12:36 +03:00
glnx_unref_object RPMOSTreeOS * os_proxy = NULL ;
glnx_unref_object RPMOSTreeSysroot * sysroot_proxy = NULL ;
g_autoptr ( GVariant ) deployments = NULL ;
2017-03-23 21:50:18 +03:00
_cleanup_peer_ GPid peer_pid = 0 ;
2015-06-13 03:19:16 +03:00
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-03-23 21:50:18 +03:00
& peer_pid ,
2016-05-31 20:12:36 +03:00
error ) )
2017-03-23 21:50:18 +03:00
return EXIT_FAILURE ;
2016-05-31 20:12:36 +03:00
if ( ! rpmostree_load_os_proxy ( sysroot_proxy , NULL ,
cancellable , & os_proxy , error ) )
2017-03-23 21:50:18 +03:00
return EXIT_FAILURE ;
2016-05-31 20:12:36 +03:00
deployments = rpmostree_sysroot_dup_deployments ( sysroot_proxy ) ;
2016-06-09 23:00:24 +03:00
if ( opt_json )
{
2016-06-14 15:34:07 +03:00
glnx_unref_object JsonBuilder * builder = json_builder_new ( ) ;
glnx_unref_object JsonGenerator * generator = json_generator_new ( ) ;
JsonNode * deployments_node = json_gvariant_serialize ( deployments ) ;
JsonNode * json_root ;
2016-06-14 16:41:36 +03:00
JsonNode * txn_node ;
2016-06-14 15:34:07 +03:00
glnx_unref_object GOutputStream * stdout_gio = g_unix_output_stream_new ( 1 , FALSE ) ;
2016-06-14 16:41:36 +03:00
GVariant * txn = get_active_txn ( sysroot_proxy ) ;
2016-06-14 15:34:07 +03:00
json_builder_begin_object ( builder ) ;
json_builder_set_member_name ( builder , " deployments " ) ;
json_builder_add_value ( builder , deployments_node ) ;
2016-06-14 16:41:36 +03:00
json_builder_set_member_name ( builder , " transaction " ) ;
if ( txn )
txn_node = json_gvariant_serialize ( txn ) ;
else
txn_node = json_node_new ( JSON_NODE_NULL ) ;
json_builder_add_value ( builder , txn_node ) ;
2016-06-14 15:34:07 +03:00
json_builder_end_object ( builder ) ;
json_root = json_builder_get_root ( builder ) ;
json_generator_set_root ( generator , json_root ) ;
json_node_free ( json_root ) ;
2016-09-23 21:31:09 +03:00
/* NB: watch out for the misleading API docs */
if ( json_generator_to_stream ( generator , stdout_gio , NULL , error ) < = 0
| | ( error ! = NULL & & * error ! = NULL ) )
2017-03-23 21:50:18 +03:00
return EXIT_FAILURE ;
2016-06-09 23:00:24 +03:00
}
else
{
if ( ! status_generic ( sysroot_proxy , os_proxy , deployments ,
cancellable , error ) )
2017-03-23 21:50:18 +03:00
return EXIT_FAILURE ;
2016-06-09 23:00:24 +03:00
}
2016-05-31 20:12:36 +03:00
2017-03-23 21:50:18 +03:00
return EXIT_SUCCESS ;
2014-06-11 21:47:10 +04:00
}