From a9a30eb08c29a9bdde08a14b620fc1a70a6f5214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Klime=C5=A1?= Date: Wed, 16 Feb 2011 17:36:50 +0100 Subject: [PATCH] cli: compare nmcli and NM versions nmcli gets NM version and compares it with its own and complains when they differ. This is to indicate that the results are not reliable, because the API could differ. '--nocheck' switches the checks off. --- cli/src/connections.c | 199 ++++++++++++++++++++++---------------- cli/src/devices.c | 36 +++++-- cli/src/network-manager.c | 14 ++- cli/src/nmcli.c | 4 + cli/src/nmcli.h | 6 +- cli/src/utils.c | 49 ++++++++++ cli/src/utils.h | 1 + 7 files changed, 214 insertions(+), 95 deletions(-) diff --git a/cli/src/connections.c b/cli/src/connections.c index 0f157b515..d08abccce 100644 --- a/cli/src/connections.c +++ b/cli/src/connections.c @@ -176,6 +176,15 @@ usage (void) " down id | uuid \n")); } +/* The real commands that do something - i.e. not 'help', etc. */ +static const char *real_con_commands[] = { + "list", + "status", + "up", + "down", + NULL +}; + /* quit main loop */ static void quit (void) @@ -1655,14 +1664,10 @@ do_connection_down (NmCli *nmc, int argc, char **argv) } } - /* TODO: fail gracefully if we are using an old N-M with user settings - * support */ - if (active) nm_client_deactivate_connection (nmc->client, active); - else { + else fprintf (stderr, _("Warning: Connection not active\n")); - } sleep (1); /* Don't quit immediatelly and give NM time to check our permissions */ error: @@ -1670,107 +1675,133 @@ error: return nmc->return_value; } +static NMCResultCode +parse_cmd (NmCli *nmc, int argc, char **argv) +{ + GError *error = NULL; + + if (argc == 0) { + if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) + goto opt_error; + nmc->return_value = do_connections_list (nmc, argc, argv); + } else { + + if (matches (*argv, "list") == 0) { + nmc->return_value = do_connections_list (nmc, argc-1, argv+1); + } + else if (matches(*argv, "status") == 0) { + if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) + goto opt_error; + nmc->return_value = do_connections_status (nmc, argc-1, argv+1); + } + else if (matches(*argv, "up") == 0) { + nmc->return_value = do_connection_up (nmc, argc-1, argv+1); + } + else if (matches(*argv, "down") == 0) { + nmc->return_value = do_connection_down (nmc, argc-1, argv+1); + } + else if (matches (*argv, "help") == 0) { + usage (); + nmc->should_wait = FALSE; + } else { + usage (); + g_string_printf (nmc->return_text, _("Error: 'con' command '%s' is not valid."), *argv); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + nmc->should_wait = FALSE; + } + } + + return nmc->return_value; + +opt_error: + g_string_printf (nmc->return_text, _("Error: %s."), error->message); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + nmc->should_wait = FALSE; + g_error_free (error); + return nmc->return_value; +} + /* callback called when connections are obtained from the settings service */ static void get_connections_cb (NMRemoteSettings *settings, gpointer user_data) { ArgsInfo *args = (ArgsInfo *) user_data; - GError *error = NULL; + /* Get the connection list */ args->nmc->system_connections = nm_remote_settings_list_connections (settings); - if (args->argc == 0) { - if (!nmc_terse_option_check (args->nmc->print_output, args->nmc->required_fields, &error)) - goto opt_error; - args->nmc->return_value = do_connections_list (args->nmc, args->argc, args->argv); - } else { - - if (matches (*args->argv, "list") == 0) { - args->nmc->return_value = do_connections_list (args->nmc, args->argc-1, args->argv+1); - } - else if (matches(*args->argv, "status") == 0) { - if (!nmc_terse_option_check (args->nmc->print_output, args->nmc->required_fields, &error)) - goto opt_error; - args->nmc->return_value = do_connections_status (args->nmc, args->argc-1, args->argv+1); - } - else if (matches(*args->argv, "up") == 0) { - args->nmc->return_value = do_connection_up (args->nmc, args->argc-1, args->argv+1); - } - else if (matches(*args->argv, "down") == 0) { - args->nmc->return_value = do_connection_down (args->nmc, args->argc-1, args->argv+1); - } - else if (matches (*args->argv, "help") == 0) { - usage (); - args->nmc->should_wait = FALSE; - } else { - usage (); - g_string_printf (args->nmc->return_text, _("Error: 'con' command '%s' is not valid."), *args->argv); - args->nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - args->nmc->should_wait = FALSE; - } - } + parse_cmd (args->nmc, args->argc, args->argv); if (!args->nmc->should_wait) quit (); - return; - -opt_error: - g_string_printf (args->nmc->return_text, _("Error: %s."), error->message); - args->nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - args->nmc->should_wait = FALSE; - g_error_free (error); - quit (); - return; } - /* Entry point function for connections-related commands: 'nmcli con' */ NMCResultCode do_connections (NmCli *nmc, int argc, char **argv) { DBusGConnection *bus; GError *error = NULL; + int i = 0; + gboolean real_cmd = FALSE; - nmc->should_wait = TRUE; - - args_info.nmc = nmc; - args_info.argc = argc; - args_info.argv = argv; - - /* connect to DBus' system bus */ - bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); - if (error || !bus) { - g_string_printf (nmc->return_text, _("Error: could not connect to D-Bus.")); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - return nmc->return_value; + if (argc == 0) + real_cmd = TRUE; + else { + while (real_con_commands[i] && matches (*argv, real_con_commands[i]) != 0) + i++; + if (real_con_commands[i] != NULL) + real_cmd = TRUE; } - /* get system settings */ - if (!(nmc->system_settings = nm_remote_settings_new (bus))) { - g_string_printf (nmc->return_text, _("Error: Could not get system settings.")); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - return nmc->return_value; + if (!real_cmd) { + /* no real execution command - no need to get connections */ + return parse_cmd (nmc, argc, argv); + } else { + if (!nmc_versions_match (nmc)) + return nmc->return_value; + nmc->should_wait = TRUE; + + args_info.nmc = nmc; + args_info.argc = argc; + args_info.argv = argv; + + /* connect to DBus' system bus */ + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (error || !bus) { + g_string_printf (nmc->return_text, _("Error: could not connect to D-Bus.")); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return nmc->return_value; + } + + /* get system settings */ + if (!(nmc->system_settings = nm_remote_settings_new (bus))) { + g_string_printf (nmc->return_text, _("Error: Could not get system settings.")); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return nmc->return_value; + + } + + /* find out whether settings service is running */ + g_object_get (nmc->system_settings, NM_REMOTE_SETTINGS_SERVICE_RUNNING, &nmc->system_settings_running, NULL); + + if (!nmc->system_settings_running) { + g_string_printf (nmc->return_text, _("Error: Can't obtain connections: settings service is not running.")); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return nmc->return_value; + } + + /* connect to signal "connections-read" - emitted when connections are fetched and ready */ + g_signal_connect (nmc->system_settings, NM_REMOTE_SETTINGS_CONNECTIONS_READ, + G_CALLBACK (get_connections_cb), &args_info); + + + dbus_g_connection_unref (bus); + + /* The rest will be done in get_connection_cb() callback. + * We need to wait for signals that connections are read. + */ + return NMC_RESULT_SUCCESS; } - - /* find out whether settings service is running */ - g_object_get (nmc->system_settings, NM_REMOTE_SETTINGS_SERVICE_RUNNING, &nmc->system_settings_running, NULL); - - if (!nmc->system_settings_running) { - g_string_printf (nmc->return_text, _("Error: Can't obtain connections: settings service is not running.")); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - return nmc->return_value; - } - - /* connect to signal "connections-read" - emitted when connections are fetched and ready */ - g_signal_connect (nmc->system_settings, NM_REMOTE_SETTINGS_CONNECTIONS_READ, - G_CALLBACK (get_connections_cb), &args_info); - - - dbus_g_connection_unref (bus); - - /* The rest will be done in get_connection_cb() callback. - * We need to wait for signals that connections are read. - */ - return NMC_RESULT_SUCCESS; } diff --git a/cli/src/devices.c b/cli/src/devices.c index 40388db71..77667bad0 100644 --- a/cli/src/devices.c +++ b/cli/src/devices.c @@ -1007,6 +1007,9 @@ do_devices_status (NmCli *nmc, int argc, char **argv) goto error; } + if (!nmc_versions_match (nmc)) + goto error; + /* Print headers */ nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES; nmc->print_fields.header_name = _("Status of devices"); @@ -1066,6 +1069,9 @@ do_devices_list (NmCli *nmc, int argc, char **argv) goto error; } + if (!nmc_versions_match (nmc)) + goto error; + nmc->get_client (nmc); devices = nm_client_get_devices (nmc->client); @@ -1216,6 +1222,9 @@ do_device_disconnect (NmCli *nmc, int argc, char **argv) goto error; } + if (!nmc_versions_match (nmc)) + goto error; + nmc->get_client (nmc); devices = nm_client_get_devices (nmc->client); for (i = 0; devices && (i < devices->len); i++) { @@ -1341,6 +1350,9 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv) goto error; } + if (!nmc_versions_match (nmc)) + goto error; + /* Print headers */ nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES; nmc->print_fields.header_name = _("WiFi scan list"); @@ -1525,12 +1537,6 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv) argv++; } - /* create NMClient */ - if (!nmc->get_client (nmc)) - goto error; - - devices = nm_client_get_devices (nmc->client); - if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) fields_str = fields_common; else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) @@ -1551,9 +1557,27 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv) goto error; } + if (!nmc_is_nm_running (nmc, &error)) { + if (error) { + g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + g_error_free (error); + } else { + g_string_printf (nmc->return_text, _("Error: NetworkManager is not running.")); + nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING; + } + goto error; + } + + if (!nmc_versions_match (nmc)) + goto error; + + /* Print headers */ nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES; nmc->print_fields.header_name = _("WiMAX NSP list"); + nmc->get_client (nmc); + devices = nm_client_get_devices (nmc->client); if (iface) { /* Device specified - list only NSPs of this interface */ for (i = 0; devices && (i < devices->len); i++) { diff --git a/cli/src/network-manager.c b/cli/src/network-manager.c index 8b4fce713..b17a9f46c 100644 --- a/cli/src/network-manager.c +++ b/cli/src/network-manager.c @@ -156,12 +156,11 @@ show_nm_status (NmCli *nmc) return nmc->return_value; } - nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES; - nmc->print_fields.header_name = _("NetworkManager status"); - print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */ - nm_running = nmc_is_nm_running (nmc, NULL); if (nm_running) { + if (!nmc_versions_match (nmc)) + goto error; + nmc->get_client (nmc); /* create NMClient */ state = nm_client_get_state (nmc->client); net_enabled_str = nm_client_networking_get_enabled (nmc->client) ? _("enabled") : _("disabled"); @@ -183,6 +182,10 @@ show_nm_status (NmCli *nmc) #endif } + nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES; + nmc->print_fields.header_name = _("NetworkManager status"); + print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */ + nmc->allowed_fields[0].value = nm_running ? _("running") : _("not running"); nmc->allowed_fields[1].value = nm_client_get_version (nmc->client); nmc->allowed_fields[2].value = nm_state_to_string (state); @@ -200,6 +203,9 @@ show_nm_status (NmCli *nmc) print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */ return NMC_RESULT_SUCCESS; + +error: + return nmc->return_value; } /* libnm-glib doesn't provide API fro Sleep method - implement D-Bus call ourselves */ diff --git a/cli/src/nmcli.c b/cli/src/nmcli.c index 832893a1f..f51779e6b 100644 --- a/cli/src/nmcli.c +++ b/cli/src/nmcli.c @@ -68,6 +68,7 @@ usage (const char *prog_name) " -m[ode] tabular|multiline output mode\n" " -f[ields] |all|common specify fields to output\n" " -e[scape] yes|no escape columns separators in values\n" + " -n[ocheck] don't check nmcli and NetworkManager versions\n" " -v[ersion] show program version\n" " -h[elp] print this help\n\n" "OBJECT\n" @@ -200,6 +201,8 @@ parse_command_line (NmCli *nmc, int argc, char **argv) return nmc->return_value; } nmc->required_fields = g_strdup (argv[1]); + } else if (matches (opt, "-nocheck") == 0) { + nmc->nocheck_ver = TRUE; } else if (matches (opt, "-version") == 0) { printf (_("nmcli tool, version %s\n"), NMCLI_VERSION); return NMC_RESULT_SUCCESS; @@ -284,6 +287,7 @@ nmc_init (NmCli *nmc) nmc->required_fields = NULL; nmc->allowed_fields = NULL; memset (&nmc->print_fields, '\0', sizeof (NmcPrintFields)); + nmc->nocheck_ver = FALSE; } static void diff --git a/cli/src/nmcli.h b/cli/src/nmcli.h index 115b276e6..90091b365 100644 --- a/cli/src/nmcli.h +++ b/cli/src/nmcli.h @@ -49,7 +49,10 @@ typedef enum { NMC_RESULT_ERROR_DEV_DISCONNECT = 6, /* NetworkManager is not running */ - NMC_RESULT_ERROR_NM_NOT_RUNNING = 7 + NMC_RESULT_ERROR_NM_NOT_RUNNING = 7, + + /* nmcli and NetworkManager versions mismatch */ + NMC_RESULT_ERROR_VERSIONS_MISMATCH = 8 } NMCResultCode; typedef enum { @@ -107,6 +110,7 @@ typedef struct _NmCli { char *required_fields; /* Required fields in output: '--fields' option */ NmcOutputField *allowed_fields; /* Array of allowed fields for particular commands */ NmcPrintFields print_fields; /* Structure with field indices to print */ + gboolean nocheck_ver; /* Don't check nmcli and NM versions: option '--nocheck' */ } NmCli; #endif /* NMC_NMCLI_H */ diff --git a/cli/src/utils.c b/cli/src/utils.c index bcc51bbd8..3c4e4f369 100644 --- a/cli/src/utils.c +++ b/cli/src/utils.c @@ -17,6 +17,9 @@ * (C) Copyright 2010 - 2011 Red Hat, Inc. */ +/* Generated configuration file */ +#include "config.h" + #include #include @@ -351,3 +354,49 @@ done: return has_owner; } +/* +* 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; +} + diff --git a/cli/src/utils.h b/cli/src/utils.h index da058f279..467054a28 100644 --- a/cli/src/utils.h +++ b/cli/src/utils.h @@ -33,5 +33,6 @@ GArray *parse_output_fields (const char *fields_str, const NmcOutputField fields gboolean nmc_terse_option_check (NMCPrintOutput print_output, const char *fields, GError **error); void print_fields (const NmcPrintFields fields, const NmcOutputField field_values[]); gboolean nmc_is_nm_running (NmCli *nmc, GError **error); +gboolean nmc_versions_match (NmCli *nmc); #endif /* NMC_UTILS_H */