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>
# include "rpmostree-builtins.h"
2015-06-13 03:19:16 +03:00
# include "rpmostree-dbus-helpers.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 ;
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 } ,
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-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 ,
GVariant * booted_deployment ,
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
const char * booted_id = NULL ;
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 " : " " ;
2014-06-13 21:16:43 +04:00
2015-06-13 03:19:16 +03:00
if ( booted_deployment )
2016-06-01 20:17:20 +03:00
g_assert ( g_variant_lookup ( booted_deployment , " id " , " &s " , & booted_id ) ) ;
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 ;
const gchar * const * origin_packages ;
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 ;
2016-06-01 20:17:20 +03:00
guint64 t = 0 ;
int serial ;
gboolean is_booted ;
const guint max_key_len = strlen ( " GPGSignature " ) ;
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 ;
dict = g_variant_dict_new ( child ) ;
/* 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 ) ) ;
g_assert ( g_variant_dict_lookup ( dict , " checksum " , " s " , & checksum ) ) ;
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) " ) ;
}
if ( g_variant_dict_lookup ( dict , " origin " , " s " , & origin_refspec ) )
2014-06-12 18:32:21 +04:00
{
2016-06-01 20:17:20 +03:00
if ( g_variant_dict_lookup ( dict , " packages " , " ^a&s " , & origin_packages ) )
2015-09-08 17:31:22 +03:00
{
2016-06-01 20:17:20 +03:00
/* Canonicalize length 0 strv to NULL */
if ( ! * origin_packages )
origin_packages = NULL ;
2015-09-08 17:31:22 +03:00
}
2016-06-01 20:17:20 +03:00
else
2015-02-11 21:06:43 +03:00
{
2016-06-01 20:17:20 +03:00
origin_packages = NULL ;
2015-02-11 21:06:43 +03:00
}
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
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-01 20:17:20 +03:00
is_booted = g_strcmp0 ( booted_id , id ) = = 0 ;
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 " ) ;
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
}
2016-06-01 20:17:20 +03:00
if ( origin_packages )
2014-06-13 21:16:43 +04:00
{
2016-06-01 20:17:20 +03:00
const char * base_checksum ;
g_assert ( g_variant_dict_lookup ( dict , " base-checksum " , " &s " , & base_checksum ) ) ;
print_kv ( " BaseCommit " , max_key_len , base_checksum ) ;
2014-06-12 18:32:21 +04:00
}
2016-06-01 20:17:20 +03:00
print_kv ( " Commit " , max_key_len , checksum ) ;
print_kv ( " OSName " , max_key_len , os_name ) ;
2014-06-12 18:32:21 +04:00
2016-06-01 20:17: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 ) ;
}
2014-06-13 21:16:43 +04:00
else
{
2016-06-01 20:17:20 +03:00
print_kv ( " GPGSignature " , max_key_len , " (unsigned) " ) ;
2014-06-13 21:16:43 +04:00
}
2014-06-11 21:47:10 +04:00
2016-06-01 20:17:20 +03:00
if ( origin_packages )
2015-04-07 20:49:21 +03:00
{
2016-06-01 20:17:20 +03:00
g_autofree char * packages_joined = g_strjoinv ( " " , ( char * * ) origin_packages ) ;
print_kv ( " Packages " , max_key_len , packages_joined ) ;
2015-04-07 20:49:21 +03:00
}
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 ,
GCancellable * cancellable ,
GError * * error )
{
int exit_status = EXIT_FAILURE ;
GOptionContext * context = g_option_context_new ( " - Get the version of the booted system " ) ;
glnx_unref_object RPMOSTreeOS * os_proxy = NULL ;
glnx_unref_object RPMOSTreeSysroot * sysroot_proxy = NULL ;
g_autoptr ( GVariant ) booted_deployment = NULL ;
g_autoptr ( GVariant ) deployments = NULL ;
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 ,
RPM_OSTREE_BUILTIN_FLAG_NONE ,
cancellable ,
& sysroot_proxy ,
error ) )
goto out ;
if ( ! rpmostree_load_os_proxy ( sysroot_proxy , NULL ,
cancellable , & os_proxy , error ) )
goto out ;
deployments = rpmostree_sysroot_dup_deployments ( sysroot_proxy ) ;
booted_deployment = rpmostree_os_dup_booted_deployment ( os_proxy ) ;
2016-06-01 20:17:20 +03:00
if ( ! status_generic ( sysroot_proxy , os_proxy , deployments ,
booted_deployment ,
cancellable , error ) )
2016-05-31 20:12:36 +03:00
goto out ;
exit_status = EXIT_SUCCESS ;
2015-06-13 03:19:16 +03:00
out :
2015-08-05 04:09:54 +03:00
/* Does nothing if using the message bus. */
rpmostree_cleanup_peer ( ) ;
2015-06-13 03:19:16 +03:00
2015-11-02 23:43:58 +03:00
return exit_status ;
2014-06-11 21:47:10 +04:00
}