2010-02-25 09:52:30 -08:00
/* nmcli - command-line tool to control NetworkManager
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
2013-01-18 15:21:00 +01:00
* ( C ) Copyright 2010 - 2013 Red Hat , Inc .
2010-02-25 09:52:30 -08:00
*/
2011-02-16 17:36:50 +01:00
/* Generated configuration file */
# include "config.h"
2010-02-25 09:52:30 -08:00
# include <stdio.h>
# include <string.h>
2013-01-16 12:28:37 +01:00
# include <stdlib.h>
# include <errno.h>
2010-02-25 09:52:30 -08:00
2012-01-05 16:30:22 +01:00
# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
2010-02-25 09:52:30 -08:00
# include <glib.h>
2010-03-18 15:39:15 +01:00
# include <glib/gi18n.h>
2011-02-10 14:21:18 +01:00
# include <dbus/dbus-glib-bindings.h>
2010-02-25 09:52:30 -08:00
# include "utils.h"
int
matches ( const char * cmd , const char * pattern )
{
int len = strlen ( cmd ) ;
if ( len > strlen ( pattern ) )
return - 1 ;
return memcmp ( pattern , cmd , len ) ;
}
int
next_arg ( int * argc , char * * * argv )
{
2012-11-16 22:43:29 +01:00
int arg_num = * argc ;
if ( arg_num > 0 ) {
2010-02-25 09:52:30 -08:00
( * argc ) - - ;
( * argv ) + + ;
}
2012-11-16 22:43:29 +01:00
if ( arg_num < = 1 )
return - 1 ;
2010-02-25 09:52:30 -08:00
return 0 ;
}
2013-04-18 11:25:49 +02:00
gboolean
nmc_arg_is_help ( const char * arg )
{
2013-04-18 12:42:54 +02:00
if ( ! arg )
return FALSE ;
2013-04-18 11:25:49 +02:00
if ( matches ( arg , " help " ) = = 0
| | ( g_str_has_prefix ( arg , " - " ) & & matches ( arg + 1 , " help " ) = = 0 )
| | ( g_str_has_prefix ( arg , " -- " ) & & matches ( arg + 2 , " help " ) = = 0 ) ) {
return TRUE ;
}
return FALSE ;
}
2013-01-16 12:26:45 +01:00
/*
* Helper function to parse command - line arguments .
* arg_arr : description of arguments to look for
* last : whether these are last expected arguments
* argc : command - line argument array
* argv : command - line argument array size
* error : error set on a failure ( when FALSE is returned )
* Returns : TRUE on success , FALSE on an error and sets ' error '
*/
gboolean
nmc_parse_args ( nmc_arg_t * arg_arr , gboolean last , int * argc , char * * * argv , GError * * error )
{
nmc_arg_t * p ;
gboolean found ;
gboolean have_mandatory ;
g_return_val_if_fail ( arg_arr ! = NULL , FALSE ) ;
g_return_val_if_fail ( error = = NULL | | * error = = NULL , FALSE ) ;
while ( * argc > 0 ) {
found = FALSE ;
for ( p = arg_arr ; p - > name ; p + + ) {
if ( strcmp ( * * argv , p - > name ) = = 0 ) {
if ( p - > found ) {
/* Don't allow repeated arguments, because the argument of the same
* name could be used later on the line for another purpose . Assume
* that ' s the case and return .
*/
return TRUE ;
}
if ( p - > has_value ) {
if ( next_arg ( argc , argv ) ! = 0 ) {
g_set_error ( error , NMCLI_ERROR , NMC_RESULT_ERROR_USER_INPUT ,
_ ( " Error: value for '%s' argument is required. " ) , * ( * argv - 1 ) ) ;
return FALSE ;
}
* ( p - > value ) = * * argv ;
}
p - > found = TRUE ;
found = TRUE ;
break ;
}
}
if ( ! found ) {
have_mandatory = TRUE ;
for ( p = arg_arr ; p - > name ; p + + ) {
if ( p - > mandatory & & ! p - > found ) {
have_mandatory = FALSE ;
break ;
}
}
if ( have_mandatory & & ! last )
return TRUE ;
if ( p & & p - > name )
g_set_error ( error , NMCLI_ERROR , NMC_RESULT_ERROR_USER_INPUT ,
_ ( " Error: Argument '%s' was expected, but '%s' provided. " ) , p - > name , * * argv ) ;
else
g_set_error ( error , NMCLI_ERROR , NMC_RESULT_ERROR_USER_INPUT ,
_ ( " Error: Unexpected argument '%s' " ) , * * argv ) ;
return FALSE ;
}
next_arg ( argc , argv ) ;
}
return TRUE ;
}
2010-03-24 23:28:00 +01:00
/*
2013-05-16 16:26:15 +02:00
* Convert SSID to a hex string representation .
2010-03-24 23:28:00 +01:00
* Caller has to free the returned string using g_free ( )
*/
char *
2013-05-16 16:26:15 +02:00
ssid_to_hex ( const char * str , gsize len )
2010-03-24 23:28:00 +01:00
{
GString * printable ;
char * printable_str ;
int i ;
if ( str = = NULL | | len = = 0 )
2012-04-28 22:54:02 +02:00
return NULL ;
2010-03-24 23:28:00 +01:00
printable = g_string_new ( NULL ) ;
for ( i = 0 ; i < len ; i + + ) {
g_string_append_printf ( printable , " %02X " , ( unsigned char ) str [ i ] ) ;
}
printable_str = g_string_free ( printable , FALSE ) ;
return printable_str ;
}
2012-01-05 16:30:22 +01:00
/*
* Converts IPv4 address from guint32 in network - byte order to text representation .
* Returns : text form of the IP or NULL ( then error is set )
*/
char *
nmc_ip4_address_as_string ( guint32 ip , GError * * error )
{
2013-07-31 23:59:50 +02:00
guint32 tmp_addr ;
2012-01-05 16:30:22 +01:00
char buf [ INET_ADDRSTRLEN ] ;
g_return_val_if_fail ( error = = NULL | | * error = = NULL , NULL ) ;
memset ( & buf , ' \0 ' , sizeof ( buf ) ) ;
2013-07-31 23:59:50 +02:00
tmp_addr = ip ;
2012-01-05 16:30:22 +01:00
if ( inet_ntop ( AF_INET , & tmp_addr , buf , INET_ADDRSTRLEN ) ) {
return g_strdup ( buf ) ;
} else {
2012-07-25 13:57:45 +02:00
g_set_error ( error , NMCLI_ERROR , 0 , _ ( " Error converting IP4 address '0x%X' to text form " ) ,
2013-07-31 23:59:50 +02:00
ntohl ( tmp_addr ) ) ;
2012-01-05 16:30:22 +01:00
return NULL ;
}
}
/*
* Converts IPv6 address in in6_addr structure to text representation .
* Returns : text form of the IP or NULL ( then error is set )
*/
char *
nmc_ip6_address_as_string ( const struct in6_addr * ip , GError * * error )
{
char buf [ INET6_ADDRSTRLEN ] ;
g_return_val_if_fail ( error = = NULL | | * error = = NULL , NULL ) ;
memset ( & buf , ' \0 ' , sizeof ( buf ) ) ;
if ( inet_ntop ( AF_INET6 , ip , buf , INET6_ADDRSTRLEN ) ) {
return g_strdup ( buf ) ;
} else {
if ( error ) {
int j ;
GString * ip6_str = g_string_new ( NULL ) ;
g_string_append_printf ( ip6_str , " %02X " , ip - > s6_addr [ 0 ] ) ;
for ( j = 1 ; j < 16 ; j + + )
g_string_append_printf ( ip6_str , " %02X " , ip - > s6_addr [ j ] ) ;
2012-07-25 13:57:45 +02:00
g_set_error ( error , NMCLI_ERROR , 0 , _ ( " Error converting IP6 address '%s' to text form " ) ,
2012-01-05 16:30:22 +01:00
ip6_str - > str ) ;
g_string_free ( ip6_str , TRUE ) ;
}
return NULL ;
}
}
2012-04-28 22:32:21 +01:00
/*
* Erase terminal line using ANSI escape sequences .
* It prints < ESC > [ 2 K sequence to erase the line and then \ r to return back
* to the beginning of the line .
*
* http : //www.termsys.demon.co.uk/vtansi.htm
*/
void
nmc_terminal_erase_line ( void )
{
printf ( " \33 [2K \r " ) ;
fflush ( stdout ) ;
}
/*
* Print animated progress for an operation .
* Repeated calls of the function will show rotating slash in terminal followed
* by the string passed in ' str ' argument .
*/
void
nmc_terminal_show_progress ( const char * str )
{
static int idx = 0 ;
const char slashes [ 4 ] = { ' | ' , ' / ' , ' - ' , ' \\ ' } ;
nmc_terminal_erase_line ( ) ;
printf ( " %c %s " , slashes [ idx + + ] , str ? str : " " ) ;
fflush ( stdout ) ;
if ( idx = = 4 )
idx = 0 ;
}
2013-04-05 23:42:56 +02:00
const char *
nmc_term_color_sequence ( NmcTermColor color )
{
switch ( color ) {
case NMC_TERM_COLOR_BLACK :
return " \33 [30m " ;
break ;
case NMC_TERM_COLOR_RED :
return " \33 [31m " ;
break ;
case NMC_TERM_COLOR_GREEN :
return " \33 [32m " ;
break ;
case NMC_TERM_COLOR_YELLOW :
return " \33 [33m " ;
break ;
case NMC_TERM_COLOR_BLUE :
return " \33 [34m " ;
break ;
case NMC_TERM_COLOR_MAGENTA :
return " \33 [35m " ;
break ;
case NMC_TERM_COLOR_CYAN :
return " \33 [36m " ;
break ;
case NMC_TERM_COLOR_WHITE :
return " \33 [37m " ;
break ;
default :
return " " ;
break ;
}
}
char *
nmc_colorize ( NmcTermColor color , const char * fmt , . . . )
{
va_list args ;
char * str ;
const char * ansi_color , * color_end ;
va_start ( args , fmt ) ;
str = g_strdup_vprintf ( fmt , args ) ;
va_end ( args ) ;
ansi_color = nmc_term_color_sequence ( color ) ;
if ( * ansi_color )
color_end = " \33 [0m " ;
else
color_end = " " ;
return g_strdup_printf ( " %s%s%s " , ansi_color , str , color_end ) ;
}
2013-01-16 12:28:37 +01:00
/*
* Convert string to signed integer .
* If required , the resulting number is checked to be in the < min , max > range .
*/
gboolean
nmc_string_to_int_base ( const char * str ,
int base ,
gboolean range_check ,
long int min ,
long int max ,
long int * value )
{
char * end ;
long int tmp ;
errno = 0 ;
tmp = strtol ( str , & end , base ) ;
if ( errno | | * end ! = ' \0 ' | | ( range_check & & ( tmp < min | | tmp > max ) ) ) {
return FALSE ;
}
* value = tmp ;
return TRUE ;
}
/*
* Convert string to unsigned integer .
* If required , the resulting number is checked to be in the < min , max > range .
*/
gboolean
nmc_string_to_uint_base ( const char * str ,
int base ,
gboolean range_check ,
unsigned long int min ,
unsigned long int max ,
unsigned long int * value )
{
char * end ;
unsigned long int tmp ;
errno = 0 ;
tmp = strtoul ( str , & end , base ) ;
if ( errno | | * end ! = ' \0 ' | | ( range_check & & ( tmp < min | | tmp > max ) ) ) {
return FALSE ;
}
* value = tmp ;
return TRUE ;
}
gboolean
nmc_string_to_int ( const char * str ,
gboolean range_check ,
long int min ,
long int max ,
long int * value )
{
return nmc_string_to_int_base ( str , 10 , range_check , min , max , value ) ;
}
gboolean
nmc_string_to_uint ( const char * str ,
gboolean range_check ,
unsigned long int min ,
unsigned long int max ,
unsigned long int * value )
{
return nmc_string_to_uint_base ( str , 10 , range_check , min , max , value ) ;
}
2013-04-06 23:25:38 +02:00
gboolean
nmc_string_to_bool ( const char * str , gboolean * val_bool , GError * * error )
{
const char * s_true [ ] = { " true " , " yes " , " on " , NULL } ;
const char * s_false [ ] = { " false " , " no " , " off " , NULL } ;
g_return_val_if_fail ( error = = NULL | | * error = = NULL , FALSE ) ;
if ( nmc_string_is_valid ( str , s_true , NULL ) )
* val_bool = TRUE ;
else if ( nmc_string_is_valid ( str , s_false , NULL ) )
* val_bool = FALSE ;
else {
g_set_error ( error , 1 , 0 ,
_ ( " '%s' is not valid; use [%s] or [%s] " ) ,
str , " true, yes, on " , " false, no, off " ) ;
return FALSE ;
}
return TRUE ;
}
2012-11-21 16:53:23 +01:00
/*
* Ask user for input and return the string .
* The caller is responsible for freeing the returned string .
*/
char *
nmc_get_user_input ( const char * ask_str )
{
char * line = NULL ;
size_t line_ln = 0 ;
2013-04-15 13:40:14 +02:00
ssize_t num ;
2012-11-21 16:53:23 +01:00
fprintf ( stdout , " %s " , ask_str ) ;
2013-04-15 13:40:14 +02:00
num = getline ( & line , & line_ln , stdin ) ;
2012-11-21 16:53:23 +01:00
/* Remove newline from the string */
2013-04-15 13:40:14 +02:00
if ( num < 1 | | ( num = = 1 & & line [ 0 ] = = ' \n ' ) ) {
2012-11-21 16:53:23 +01:00
g_free ( line ) ;
line = NULL ;
} else {
2013-04-15 13:40:14 +02:00
if ( line [ num - 1 ] = = ' \n ' )
line [ num - 1 ] = ' \0 ' ;
2012-11-21 16:53:23 +01:00
}
return line ;
}
2012-11-22 11:56:06 +01:00
/*
* Split string in ' line ' according to ' delim ' to ( argument ) array .
*/
int
nmc_string_to_arg_array ( const char * line , const char * delim , char * * * argv , int * argc )
{
int i = 0 ;
char * * arr ;
arr = g_strsplit_set ( line ? line : " " , delim ? delim : " \t " , 0 ) ;
while ( arr & & arr [ i ] )
i + + ;
* argc = i ;
* argv = arr ;
return 0 ;
}
2013-04-08 09:25:44 +02:00
/*
* Check whether ' input ' is contained in ' allowed ' array . It performs case
* insensitive comparison and supports shortcut strings if they are unique .
* Returns : a pointer to found string in allowed array on success or NULL .
* On failure : error - > code : 0 - string not found ; 1 - string is ambiguous
*/
const char *
nmc_string_is_valid ( const char * input , const char * * allowed , GError * * error )
{
const char * * p ;
size_t input_ln , p_len ;
gboolean prev_match = FALSE ;
const char * ret = NULL ;
g_return_val_if_fail ( error = = NULL | | * error = = NULL , NULL ) ;
if ( ! input | | ! * input )
goto finish ;
input_ln = strlen ( input ) ;
for ( p = allowed ; p & & * p ; p + + ) {
p_len = strlen ( * p ) ;
if ( g_ascii_strncasecmp ( input , * p , input_ln ) = = 0 ) {
if ( input_ln = = p_len ) {
ret = * p ;
break ;
}
if ( ! prev_match )
ret = * p ;
else {
g_set_error ( error , 1 , 1 , _ ( " '%s' is ambiguous (%s x %s) " ) ,
input , ret , * p ) ;
return NULL ;
}
prev_match = TRUE ;
}
}
finish :
if ( ret = = NULL ) {
char * valid_vals = g_strjoinv ( " , " , ( char * * ) allowed ) ;
2013-09-05 19:16:12 +02:00
if ( ! input | | ! * input ) {
g_set_error ( error , 1 , 0 , _ ( " missing name, try one of [%s] " ) ,
valid_vals ) ;
} else {
g_set_error ( error , 1 , 0 , _ ( " '%s' not among [%s] " ) ,
input ? input : " " , valid_vals ) ;
}
2013-04-08 09:25:44 +02:00
g_free ( valid_vals ) ;
}
return ret ;
}
2013-01-18 15:21:00 +01:00
/*
* Convert string array ( char * * ) to GSList .
*
* Returns : pointer to newly created GSList . Caller should free it .
*/
GSList *
nmc_util_strv_to_slist ( char * * strv )
{
GSList * list = NULL ;
guint i = 0 ;
while ( strv & & strv [ i ] )
list = g_slist_prepend ( list , g_strdup ( strv [ i + + ] ) ) ;
return g_slist_reverse ( list ) ;
}
/*
* Wrapper function for g_strsplit_set ( ) that removes empty strings
* from the vector as they are not useful in most cases .
*/
char * *
nmc_strsplit_set ( const char * str , const char * delimiter , int max_tokens )
{
char * * result ;
uint i ;
uint j ;
result = g_strsplit_set ( str , delimiter , max_tokens ) ;
/* remove empty strings */
for ( i = 0 ; result & & result [ i ] ; i + + ) {
if ( * ( result [ i ] ) = = ' \0 ' ) {
g_free ( result [ i ] ) ;
for ( j = i ; result [ j ] ; j + + )
result [ j ] = result [ j + 1 ] ;
i - - ;
}
}
return result ;
}
2010-04-26 17:32:18 +02:00
/*
* Find out how many columns an UTF - 8 string occupies on the screen
*/
int
nmc_string_screen_width ( const char * start , const char * end )
{
int width = 0 ;
if ( end = = NULL )
end = start + strlen ( start ) ;
while ( start < end ) {
width + = g_unichar_iswide ( g_utf8_get_char ( start ) ) ? 2 : g_unichar_iszerowidth ( g_utf8_get_char ( start ) ) ? 0 : 1 ;
start = g_utf8_next_char ( start ) ;
}
return width ;
}
2012-01-03 15:07:17 +01:00
void
2013-03-05 15:50:11 +01:00
set_val_str ( NmcOutputField fields_array [ ] , guint32 idx , char * value )
2012-01-03 15:07:17 +01:00
{
fields_array [ idx ] . value = value ;
2013-05-22 08:36:09 +02:00
fields_array [ idx ] . value_is_array = FALSE ;
fields_array [ idx ] . free_value = TRUE ;
}
void
set_val_strc ( NmcOutputField fields_array [ ] , guint32 idx , const char * value )
{
fields_array [ idx ] . value = ( char * ) value ;
fields_array [ idx ] . value_is_array = FALSE ;
fields_array [ idx ] . free_value = FALSE ;
2012-01-03 15:07:17 +01:00
}
void
2013-03-05 15:50:11 +01:00
set_val_arr ( NmcOutputField fields_array [ ] , guint32 idx , char * * value )
2012-01-03 15:07:17 +01:00
{
fields_array [ idx ] . value = value ;
2013-05-22 08:36:09 +02:00
fields_array [ idx ] . value_is_array = TRUE ;
fields_array [ idx ] . free_value = TRUE ;
}
void
set_val_arrc ( NmcOutputField fields_array [ ] , guint32 idx , const char * * value )
{
fields_array [ idx ] . value = ( char * * ) value ;
fields_array [ idx ] . value_is_array = TRUE ;
fields_array [ idx ] . free_value = FALSE ;
2012-01-03 15:07:17 +01:00
}
2013-03-25 10:44:15 -04:00
/*
* Free ' value ' members in array of NmcOutputField
*/
void
nmc_free_output_field_values ( NmcOutputField fields_array [ ] )
{
2013-05-22 08:36:09 +02:00
NmcOutputField * iter = fields_array ;
while ( iter & & iter - > name ) {
if ( iter - > free_value ) {
if ( iter - > value_is_array )
g_strfreev ( ( char * * ) iter - > value ) ;
else
g_free ( ( char * ) iter - > value ) ;
iter - > value = NULL ;
}
iter + + ;
2013-03-25 10:44:15 -04:00
}
}
2010-03-18 15:39:15 +01:00
/*
* Parse comma separated fields in ' fields_str ' according to ' fields_array ' .
* IN : ' field_str ' : comma - separated fields names
* ' fields_array ' : array of allowed fields
* RETURN : GArray with indices representing fields in ' fields_array ' .
2010-03-20 14:08:06 +01:00
* Caller is responsible to free it .
2010-03-18 15:39:15 +01:00
*/
GArray *
parse_output_fields ( const char * fields_str , const NmcOutputField fields_array [ ] , GError * * error )
{
char * * fields , * * iter ;
GArray * array ;
int i ;
g_return_val_if_fail ( error = = NULL | | * error = = NULL , NULL ) ;
array = g_array_new ( FALSE , FALSE , sizeof ( int ) ) ;
/* Split supplied fields string */
fields = g_strsplit_set ( fields_str , " , " , - 1 ) ;
for ( iter = fields ; iter & & * iter ; iter + + ) {
for ( i = 0 ; fields_array [ i ] . name ; i + + ) {
if ( strcasecmp ( * iter , fields_array [ i ] . name ) = = 0 ) {
g_array_append_val ( array , i ) ;
break ;
}
}
if ( fields_array [ i ] . name = = NULL ) {
if ( ! strcasecmp ( * iter , " all " ) | | ! strcasecmp ( * iter , " common " ) )
2012-07-25 13:57:45 +02:00
g_set_error ( error , NMCLI_ERROR , 0 , _ ( " field '%s' has to be alone " ) , * iter ) ;
2010-03-18 15:39:15 +01:00
else
2012-07-25 13:57:45 +02:00
g_set_error ( error , NMCLI_ERROR , 1 , _ ( " invalid field '%s' " ) , * iter ) ;
2010-03-18 15:39:15 +01:00
g_array_free ( array , TRUE ) ;
array = NULL ;
goto done ;
}
}
done :
2010-03-19 15:46:25 +01:00
if ( fields )
g_strfreev ( fields ) ;
2010-03-18 15:39:15 +01:00
return array ;
}
2010-03-22 18:43:28 +01:00
gboolean
nmc_terse_option_check ( NMCPrintOutput print_output , const char * fields , GError * * error )
{
g_return_val_if_fail ( error = = NULL | | * error = = NULL , FALSE ) ;
if ( print_output = = NMC_PRINT_TERSE ) {
if ( ! fields ) {
2012-07-25 13:57:45 +02:00
g_set_error_literal ( error , NMCLI_ERROR , 0 , _ ( " Option '--terse' requires specifying '--fields' " ) ) ;
2010-03-22 18:43:28 +01:00
return FALSE ;
} else if ( ! strcasecmp ( fields , " all " )
| | ! strcasecmp ( fields , " common " ) ) {
2012-07-25 13:57:45 +02:00
g_set_error ( error , NMCLI_ERROR , 0 , _ ( " Option '--terse' requires specific '--fields' option values , not '%s' " ) , fields ) ;
2010-03-22 18:43:28 +01:00
return FALSE ;
}
}
return TRUE ;
}
2013-05-22 08:36:09 +02:00
NmcOutputField *
nmc_dup_fields_array ( NmcOutputField fields [ ] , size_t size , guint32 flags )
{
NmcOutputField * row ;
row = g_malloc0 ( size ) ;
memcpy ( row , fields , size ) ;
row [ 0 ] . flags = flags ;
return row ;
}
void
nmc_empty_output_fields ( NmCli * nmc )
{
guint i ;
/* Free values in field structure */
for ( i = 0 ; i < nmc - > output_data - > len ; i + + ) {
NmcOutputField * fld_arr = g_ptr_array_index ( nmc - > output_data , i ) ;
nmc_free_output_field_values ( fld_arr ) ;
}
/* Empty output_data array */
if ( nmc - > output_data - > len > 0 )
g_ptr_array_remove_range ( nmc - > output_data , 0 , nmc - > output_data - > len ) ;
2013-10-03 10:08:22 -04:00
if ( nmc - > print_fields . indices ) {
g_array_free ( nmc - > print_fields . indices , TRUE ) ;
nmc - > print_fields . indices = NULL ;
}
2013-05-22 08:36:09 +02:00
}
static char *
get_value_to_print ( NmcOutputField * fields ,
gboolean field_name ,
const char * not_set_str ,
gboolean * dealloc )
{
gboolean is_array = fields - > value_is_array ;
char * value ;
if ( field_name )
value = _ ( fields - > name_l10n ) ;
else
value = fields - > value ?
( is_array ? g_strjoinv ( " | " , ( char * * ) fields - > value ) :
( char * ) fields - > value ) :
( char * ) not_set_str ;
* dealloc = fields - > value & & is_array & & ! field_name ;
return value ;
}
2010-03-20 14:08:06 +01:00
/*
* Print both headers or values of ' field_values ' array .
2013-05-22 08:36:09 +02:00
* Entries to print and their order are specified via indices in
* ' nmc - > print_fields . indices ' array .
* Various flags influencing the output of fields are set up in the first item
* of ' field_values ' array .
2010-03-20 14:08:06 +01:00
*/
2010-03-18 15:39:15 +01:00
void
2013-05-22 08:36:09 +02:00
print_required_fields ( NmCli * nmc , const NmcOutputField field_values [ ] )
2010-03-18 15:39:15 +01:00
{
GString * str ;
int width1 , width2 ;
int table_width = 0 ;
char * line = NULL ;
char * indent_str ;
2012-06-04 12:25:43 +02:00
const char * not_set_str = " -- " ;
2012-01-03 15:07:17 +01:00
int i ;
2013-05-22 08:36:09 +02:00
const NmcPrintFields fields = nmc - > print_fields ;
gboolean multiline = nmc - > multiline_output ;
gboolean terse = ( nmc - > print_output = = NMC_PRINT_TERSE ) ;
gboolean pretty = ( nmc - > print_output = = NMC_PRINT_PRETTY ) ;
gboolean escape = nmc - > escape_values ;
gboolean main_header_add = field_values [ 0 ] . flags & NMC_OF_FLAG_MAIN_HEADER_ADD ;
gboolean main_header_only = field_values [ 0 ] . flags & NMC_OF_FLAG_MAIN_HEADER_ONLY ;
gboolean field_names = field_values [ 0 ] . flags & NMC_OF_FLAG_FIELD_NAMES ;
gboolean section_prefix = field_values [ 0 ] . flags & NMC_OF_FLAG_SECTION_PREFIX ;
2010-03-24 19:05:35 +01:00
gboolean main_header = main_header_add | | main_header_only ;
2010-03-18 15:39:15 +01:00
2010-03-20 14:08:06 +01:00
/* No headers are printed in terse mode:
2010-03-22 18:43:28 +01:00
* - neither main header nor field ( column ) names
2010-03-20 14:08:06 +01:00
*/
2010-03-24 19:05:35 +01:00
if ( ( main_header_only | | field_names ) & & terse )
2010-03-18 15:39:15 +01:00
return ;
if ( multiline ) {
/* --- Multiline mode --- */
2010-03-20 14:08:06 +01:00
enum { ML_HEADER_WIDTH = 79 } ;
2011-09-07 12:20:56 +02:00
enum { ML_VALUE_INDENT = 40 } ;
2010-03-22 18:43:28 +01:00
if ( main_header & & pretty ) {
/* Print the main header */
2010-04-26 17:32:18 +02:00
int header_width = nmc_string_screen_width ( fields . header_name , NULL ) + 4 ;
2010-03-20 14:08:06 +01:00
table_width = header_width < ML_HEADER_WIDTH ? ML_HEADER_WIDTH : header_width ;
line = g_strnfill ( ML_HEADER_WIDTH , ' = ' ) ;
2010-03-18 15:39:15 +01:00
width1 = strlen ( fields . header_name ) ;
2010-04-26 17:32:18 +02:00
width2 = nmc_string_screen_width ( fields . header_name , NULL ) ;
2010-03-18 15:39:15 +01:00
printf ( " %s \n " , line ) ;
printf ( " %*s \n " , ( table_width + width2 ) / 2 + width1 - width2 , fields . header_name ) ;
printf ( " %s \n " , line ) ;
g_free ( line ) ;
}
/* Print values */
2010-03-24 19:05:35 +01:00
if ( ! main_header_only & & ! field_names ) {
2010-03-18 15:39:15 +01:00
for ( i = 0 ; i < fields . indices - > len ; i + + ) {
char * tmp ;
2012-01-03 15:07:17 +01:00
int idx = g_array_index ( fields . indices , int , i ) ;
2013-05-22 08:36:09 +02:00
gboolean is_array = field_values [ idx ] . value_is_array ;
2012-01-03 15:07:17 +01:00
/* section prefix can't be an array */
2013-05-22 08:36:09 +02:00
g_assert ( ! is_array | | ! section_prefix | | idx ! = 0 ) ;
2012-01-03 15:07:17 +01:00
2010-03-24 19:05:35 +01:00
if ( section_prefix & & idx = = 0 ) /* The first field is section prefix */
continue ;
2012-01-03 15:07:17 +01:00
2013-05-22 08:36:09 +02:00
if ( is_array ) {
2012-01-03 15:07:17 +01:00
/* value is a null-terminated string array */
const char * * p ;
int j ;
for ( p = ( const char * * ) field_values [ idx ] . value , j = 1 ; p & & * p ; p + + , j + + ) {
2013-05-22 08:36:09 +02:00
tmp = g_strdup_printf ( " %s%s%s[%d]: " ,
section_prefix ? ( const char * ) field_values [ 0 ] . value : " " ,
section_prefix ? " . " : " " ,
_ ( field_values [ idx ] . name_l10n ) ,
j ) ;
2013-05-28 09:21:02 +02:00
width1 = strlen ( tmp ) ;
width2 = nmc_string_screen_width ( tmp , NULL ) ;
printf ( " %-*s%s \n " , terse ? 0 : ML_VALUE_INDENT + width1 - width2 , tmp ,
* p ? * p : not_set_str ) ;
2012-01-03 15:07:17 +01:00
g_free ( tmp ) ;
}
} else {
/* value is a string */
const char * hdr_name = ( const char * ) field_values [ 0 ] . value ;
const char * val = ( const char * ) field_values [ idx ] . value ;
2013-05-22 08:36:09 +02:00
tmp = g_strdup_printf ( " %s%s%s: " ,
section_prefix ? hdr_name : " " ,
section_prefix ? " . " : " " ,
_ ( field_values [ idx ] . name_l10n ) ) ;
2013-05-28 09:21:02 +02:00
width1 = strlen ( tmp ) ;
width2 = nmc_string_screen_width ( tmp , NULL ) ;
printf ( " %-*s%s \n " , terse ? 0 : ML_VALUE_INDENT + width1 - width2 , tmp ,
val ? val : not_set_str ) ;
2012-01-03 15:07:17 +01:00
g_free ( tmp ) ;
}
2010-03-18 15:39:15 +01:00
}
if ( pretty ) {
2010-03-20 14:08:06 +01:00
line = g_strnfill ( ML_HEADER_WIDTH , ' - ' ) ;
2010-03-18 15:39:15 +01:00
printf ( " %s \n " , line ) ;
g_free ( line ) ;
}
}
return ;
}
/* --- Tabular mode: each line = one object --- */
str = g_string_new ( NULL ) ;
for ( i = 0 ; i < fields . indices - > len ; i + + ) {
2012-01-03 15:07:17 +01:00
int idx = g_array_index ( fields . indices , int , i ) ;
2013-05-22 08:36:09 +02:00
gboolean dealloc ;
char * value = get_value_to_print ( ( NmcOutputField * ) field_values + idx , field_names , not_set_str , & dealloc ) ;
2012-01-03 15:07:17 +01:00
2010-03-18 15:39:15 +01:00
if ( terse ) {
if ( escape ) {
const char * p = value ;
while ( * p ) {
if ( * p = = ' : ' | | * p = = ' \\ ' )
g_string_append_c ( str , ' \\ ' ) ; /* Escaping by '\' */
g_string_append_c ( str , * p ) ;
p + + ;
}
}
2012-01-03 15:07:17 +01:00
else
2010-03-18 15:39:15 +01:00
g_string_append_printf ( str , " %s " , value ) ;
g_string_append_c ( str , ' : ' ) ; /* Column separator */
} else {
width1 = strlen ( value ) ;
2010-04-26 17:32:18 +02:00
width2 = nmc_string_screen_width ( value , NULL ) ; /* Width of the string (in screen colums) */
2012-01-03 15:07:17 +01:00
g_string_append_printf ( str , " %-*s " , field_values [ idx ] . width + width1 - width2 , strlen ( value ) > 0 ? value : " -- " ) ;
2010-03-18 15:39:15 +01:00
g_string_append_c ( str , ' ' ) ; /* Column separator */
table_width + = field_values [ idx ] . width + width1 - width2 + 1 ;
}
2012-01-03 15:07:17 +01:00
2013-05-22 08:36:09 +02:00
if ( dealloc )
2012-01-03 15:07:17 +01:00
g_free ( value ) ;
2010-03-18 15:39:15 +01:00
}
2010-03-22 18:43:28 +01:00
/* Print the main table header */
if ( main_header & & pretty ) {
2010-04-26 17:32:18 +02:00
int header_width = nmc_string_screen_width ( fields . header_name , NULL ) + 4 ;
2010-03-20 14:08:06 +01:00
table_width = table_width < header_width ? header_width : table_width ;
2010-03-18 15:39:15 +01:00
line = g_strnfill ( table_width , ' = ' ) ;
width1 = strlen ( fields . header_name ) ;
2010-04-26 17:32:18 +02:00
width2 = nmc_string_screen_width ( fields . header_name , NULL ) ;
2010-03-18 15:39:15 +01:00
printf ( " %s \n " , line ) ;
printf ( " %*s \n " , ( table_width + width2 ) / 2 + width1 - width2 , fields . header_name ) ;
printf ( " %s \n " , line ) ;
g_free ( line ) ;
}
2010-03-20 14:08:06 +01:00
/* Print actual values */
2010-03-24 19:05:35 +01:00
if ( ! main_header_only & & str - > len > 0 ) {
2010-03-18 15:39:15 +01:00
g_string_truncate ( str , str - > len - 1 ) ; /* Chop off last column separator */
if ( fields . indent > 0 ) {
indent_str = g_strnfill ( fields . indent , ' ' ) ;
2010-03-20 14:08:06 +01:00
g_string_prepend ( str , indent_str ) ;
2010-03-18 15:39:15 +01:00
g_free ( indent_str ) ;
}
printf ( " %s \n " , str - > str ) ;
}
2010-03-20 14:08:06 +01:00
/* Print horizontal separator */
2010-03-24 19:05:35 +01:00
if ( ! main_header_only & & field_names & & pretty ) {
2010-03-18 15:39:15 +01:00
if ( str - > len > 0 ) {
line = g_strnfill ( table_width , ' - ' ) ;
printf ( " %s \n " , line ) ;
g_free ( line ) ;
}
}
g_string_free ( str , TRUE ) ;
}
2013-05-22 08:36:09 +02:00
/*
* Print nmc - > output_data
*
* It first finds out maximal string length in columns and fill the value to
* ' width ' member of NmcOutputField , so that columns in tabular output are
* properly aligned . Then each object ( row in tabular ) is printed using
* print_required_fields ( ) function .
*/
void
print_data ( NmCli * nmc )
{
int i , j ;
size_t len ;
NmcOutputField * row ;
int num_fields = 0 ;
if ( ! nmc - > output_data | | nmc - > output_data - > len < 1 )
return ;
/* How many fields? */
row = g_ptr_array_index ( nmc - > output_data , 0 ) ;
while ( row - > name ) {
num_fields + + ;
row + + ;
}
/* Find out maximal string lengths */
for ( i = 0 ; i < num_fields ; i + + ) {
size_t max_width = 0 ;
for ( j = 0 ; j < nmc - > output_data - > len ; j + + ) {
gboolean field_names , dealloc ;
char * value ;
row = g_ptr_array_index ( nmc - > output_data , j ) ;
field_names = row [ 0 ] . flags & NMC_OF_FLAG_FIELD_NAMES ;
value = get_value_to_print ( row + i , field_names , " -- " , & dealloc ) ;
len = nmc_string_screen_width ( value , NULL ) ;
max_width = len > max_width ? len : max_width ;
if ( dealloc )
g_free ( value ) ;
}
for ( j = 0 ; j < nmc - > output_data - > len ; j + + ) {
row = g_ptr_array_index ( nmc - > output_data , j ) ;
row [ i ] . width = max_width + 1 ;
}
}
/* Now we can print the data. */
for ( i = 0 ; i < nmc - > output_data - > len ; i + + ) {
row = g_ptr_array_index ( nmc - > output_data , i ) ;
print_required_fields ( nmc , row ) ;
}
}
2011-02-16 17:36:50 +01:00
/*
* Compare versions of nmcli and NM daemon .
* Return : TRUE - the versions match ( when only major and minor match , print a warning )
* FALSE - versions mismatch
*/
gboolean
nmc_versions_match ( NmCli * nmc )
{
const char * nm_ver = NULL ;
const char * dot ;
gboolean match = FALSE ;
g_return_val_if_fail ( nmc ! = NULL , FALSE ) ;
/* --nocheck option - don't compare the versions */
if ( nmc - > nocheck_ver )
return TRUE ;
nmc - > get_client ( nmc ) ;
nm_ver = nm_client_get_version ( nmc - > client ) ;
if ( nm_ver ) {
if ( ! strcmp ( nm_ver , VERSION ) )
match = TRUE ;
else {
dot = strchr ( nm_ver , ' . ' ) ;
if ( dot ) {
dot = strchr ( dot + 1 , ' . ' ) ;
if ( dot & & ! strncmp ( nm_ver , VERSION , dot - nm_ver ) ) {
fprintf ( stderr ,
_ ( " Warning: nmcli (%s) and NetworkManager (%s) versions don't match. Use --nocheck to suppress the warning. \n " ) ,
VERSION , nm_ver ) ;
match = TRUE ;
}
}
}
}
if ( ! match ) {
g_string_printf ( nmc - > return_text , _ ( " Error: nmcli (%s) and NetworkManager (%s) versions don't match. Force execution using --nocheck, but the results are unpredictable. " ) ,
VERSION , nm_ver ? nm_ver : _ ( " unknown " ) ) ;
nmc - > return_value = NMC_RESULT_ERROR_VERSIONS_MISMATCH ;
}
return match ;
}