4646#include "network-internal.h"
4747#include "network-util.h"
4848#include "pager.h"
49+ #include "parse-argument.h"
4950#include "parse-util.h"
5051#include "pretty-print.h"
5152#include "set.h"
@@ -75,6 +76,110 @@ static bool arg_all = false;
7576static bool arg_stats = false;
7677static bool arg_full = false;
7778static unsigned arg_lines = 10 ;
79+ static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF ;
80+
81+ static int get_description (JsonVariant * * ret ) {
82+ _cleanup_ (sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
83+ _cleanup_ (sd_bus_message_unrefp ) sd_bus_message * reply = NULL ;
84+ _cleanup_ (sd_bus_flush_close_unrefp ) sd_bus * bus = NULL ;
85+ const char * text = NULL ;
86+ int r ;
87+
88+ r = sd_bus_open_system (& bus );
89+ if (r < 0 )
90+ return log_error_errno (r , "Failed to connect system bus: %m" );
91+
92+ r = bus_call_method (bus , bus_network_mgr , "Describe" , & error , & reply , NULL );
93+ if (r < 0 )
94+ return log_error_errno (r , "Failed to get description: %s" , bus_error_message (& error , r ));
95+
96+ r = sd_bus_message_read (reply , "s" , & text );
97+ if (r < 0 )
98+ return bus_log_parse_error (r );
99+
100+ r = json_parse (text , 0 , ret , NULL , NULL );
101+ if (r < 0 )
102+ return log_error_errno (r , "Failed to parse JSON: %m" );
103+
104+ return 0 ;
105+ }
106+
107+ static int dump_manager_description (void ) {
108+ _cleanup_ (json_variant_unrefp ) JsonVariant * v = NULL ;
109+ int r ;
110+
111+ r = get_description (& v );
112+ if (r < 0 )
113+ return r ;
114+
115+ json_variant_dump (v , arg_json_format_flags , NULL , NULL );
116+ return 0 ;
117+ }
118+
119+ static int dump_link_description (char * * patterns ) {
120+ _cleanup_ (json_variant_unrefp ) JsonVariant * v = NULL ;
121+ _cleanup_free_ bool * matched_patterns = NULL ;
122+ JsonVariant * i ;
123+ size_t c = 0 ;
124+ int r ;
125+
126+ r = get_description (& v );
127+ if (r < 0 )
128+ return r ;
129+
130+ matched_patterns = new0 (bool , strv_length (patterns ));
131+ if (!matched_patterns )
132+ return log_oom ();
133+
134+ JSON_VARIANT_ARRAY_FOREACH (i , json_variant_by_key (v , "Interfaces" )) {
135+ char ifindex_str [DECIMAL_STR_MAX (intmax_t )];
136+ const char * name ;
137+ intmax_t index ;
138+ size_t pos ;
139+
140+ name = json_variant_string (json_variant_by_key (i , "Name" ));
141+ index = json_variant_integer (json_variant_by_key (i , "Index" ));
142+ xsprintf (ifindex_str , "%ji" , index );
143+
144+ if (!strv_fnmatch_full (patterns , ifindex_str , 0 , & pos ) &&
145+ !strv_fnmatch_full (patterns , name , 0 , & pos )) {
146+ bool match = false;
147+ JsonVariant * a ;
148+
149+ JSON_VARIANT_ARRAY_FOREACH (a , json_variant_by_key (i , "AlternativeNames" ))
150+ if (strv_fnmatch_full (patterns , json_variant_string (a ), 0 , & pos )) {
151+ match = true;
152+ break ;
153+ }
154+
155+ if (!match )
156+ continue ;
157+ }
158+
159+ matched_patterns [pos ] = true;
160+ json_variant_dump (i , arg_json_format_flags , NULL , NULL );
161+ c ++ ;
162+ }
163+
164+ /* Look if we matched all our arguments that are not globs. It is OK for a glob to match
165+ * nothing, but not for an exact argument. */
166+ for (size_t pos = 0 ; pos < strv_length (patterns ); pos ++ ) {
167+ if (matched_patterns [pos ])
168+ continue ;
169+
170+ if (string_is_glob (patterns [pos ]))
171+ log_debug ("Pattern \"%s\" doesn't match any interface, ignoring." ,
172+ patterns [pos ]);
173+ else
174+ return log_error_errno (SYNTHETIC_ERRNO (ENODEV ),
175+ "Interface \"%s\" not found." , patterns [pos ]);
176+ }
177+
178+ if (c == 0 )
179+ log_warning ("No interfaces matched." );
180+
181+ return 0 ;
182+ }
78183
79184static void operational_state_to_color (const char * name , const char * state , const char * * on , const char * * off ) {
80185 if (STRPTR_IN_SET (state , "routable" , "enslaved" ) ||
@@ -674,6 +779,13 @@ static int list_links(int argc, char *argv[], void *userdata) {
674779 TableCell * cell ;
675780 int c , r ;
676781
782+ if (arg_json_format_flags != JSON_FORMAT_OFF ) {
783+ if (arg_all || argc <= 1 )
784+ return dump_manager_description ();
785+ else
786+ return dump_link_description (strv_skip (argv , 1 ));
787+ }
788+
677789 r = sd_netlink_open (& rtnl );
678790 if (r < 0 )
679791 return log_error_errno (r , "Failed to connect to netlink: %m" );
@@ -2238,6 +2350,13 @@ static int link_status(int argc, char *argv[], void *userdata) {
22382350 _cleanup_ (link_info_array_freep ) LinkInfo * links = NULL ;
22392351 int r , c ;
22402352
2353+ if (arg_json_format_flags != JSON_FORMAT_OFF ) {
2354+ if (arg_all || argc <= 1 )
2355+ return dump_manager_description ();
2356+ else
2357+ return dump_link_description (strv_skip (argv , 1 ));
2358+ }
2359+
22412360 (void ) pager_open (arg_pager_flags );
22422361
22432362 r = sd_bus_open_system (& bus );
@@ -2728,6 +2847,8 @@ static int help(void) {
27282847 " -s --stats Show detailed link statics\n"
27292848 " -l --full Do not ellipsize output\n"
27302849 " -n --lines=INTEGER Number of journal entries to show\n"
2850+ " --json=pretty|short|off\n"
2851+ " Generate JSON output\n"
27312852 "\nSee the %s for details.\n" ,
27322853 program_invocation_short_name ,
27332854 ansi_highlight (),
@@ -2743,6 +2864,7 @@ static int parse_argv(int argc, char *argv[]) {
27432864 ARG_VERSION = 0x100 ,
27442865 ARG_NO_PAGER ,
27452866 ARG_NO_LEGEND ,
2867+ ARG_JSON ,
27462868 };
27472869
27482870 static const struct option options [] = {
@@ -2754,10 +2876,11 @@ static int parse_argv(int argc, char *argv[]) {
27542876 { "stats" , no_argument , NULL , 's' },
27552877 { "full" , no_argument , NULL , 'l' },
27562878 { "lines" , required_argument , NULL , 'n' },
2879+ { "json" , required_argument , NULL , ARG_JSON },
27572880 {}
27582881 };
27592882
2760- int c ;
2883+ int c , r ;
27612884
27622885 assert (argc >= 0 );
27632886 assert (argv );
@@ -2798,6 +2921,12 @@ static int parse_argv(int argc, char *argv[]) {
27982921 "Failed to parse lines '%s'" , optarg );
27992922 break ;
28002923
2924+ case ARG_JSON :
2925+ r = parse_json_argument (optarg , & arg_json_format_flags );
2926+ if (r <= 0 )
2927+ return r ;
2928+ break ;
2929+
28012930 case '?' :
28022931 return - EINVAL ;
28032932
0 commit comments