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 */