diff --git a/cli/src/connections.c b/cli/src/connections.c index ae09fe0b5f..8f671cd72c 100644 --- a/cli/src/connections.c +++ b/cli/src/connections.c @@ -53,6 +53,37 @@ #include "connections.h" +/* Available field for 'con status' */ +static NmcOutputField nmc_fields_con_status[] = { + {"NAME", N_("NAME"), 25, NULL, 0}, /* 0 */ + {"UUID", N_("UUID"), 38, NULL, 0}, /* 1 */ + {"DEVICES", N_("DEVICES"), 10, NULL, 0}, /* 2 */ + {"SCOPE", N_("SCOPE"), 8, NULL, 0}, /* 3 */ + {"DEFAULT", N_("DEFAULT"), 8, NULL, 0}, /* 4 */ + {"DBUS-SERVICE", N_("DBUS-SERVICE"), 45, NULL, 0}, /* 5 */ + {"SPEC-OBJECT", N_("SPEC-OBJECT"), 10, NULL, 0}, /* 6 */ + {"VPN", N_("VPN"), 5, NULL, 0}, /* 7 */ + {NULL, NULL, 0, NULL, 0} +}; +#define NMC_FIELDS_CON_STATUS_ALL "NAME,UUID,DEVICES,SCOPE,DEFAULT,VPN,DBUS-SERVICE,SPEC-OBJECT" +#define NMC_FIELDS_CON_STATUS_COMMON "NAME,UUID,DEVICES,SCOPE,DEFAULT,VPN" + +/* Available field for 'con list' */ +static NmcOutputField nmc_fields_con_list[] = { + {"NAME", N_("NAME"), 25, NULL, 0}, /* 0 */ + {"UUID", N_("UUID"), 38, NULL, 0}, /* 1 */ + {"TYPE", N_("TYPE"), 17, NULL, 0}, /* 2 */ + {"SCOPE", N_("SCOPE"), 8, NULL, 0}, /* 3 */ + {"TIMESTAMP", N_("TIMESTAMP"), 12, NULL, 0}, /* 4 */ + {"TIMESTAMP-REAL", N_("TIMESTAMP-REAL"), 34, NULL, 0}, /* 5 */ + {"AUTOCONNECT", N_("AUTOCONNECT"), 13, NULL, 0}, /* 6 */ + {"READONLY", N_("READONLY"), 10, NULL, 0}, /* 7 */ + {NULL, NULL, 0, NULL, 0} +}; +#define NMC_FIELDS_CON_LIST_ALL "NAME,UUID,TYPE,SCOPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,READONLY" +#define NMC_FIELDS_CON_LIST_COMMON "NAME,UUID,TYPE,SCOPE,TIMESTAMP-REAL" + + typedef struct { NmCli *nmc; int argc; @@ -102,17 +133,31 @@ static void show_connection (NMConnection *data, gpointer user_data) { NMConnection *connection = (NMConnection *) data; + NmCli *nmc = (NmCli *) user_data; NMSettingConnection *s_con; - const char *id; - const char *uuid; - const char *con_type; + guint64 timestamp; + char *timestamp_str; + char timestamp_real_str[64]; s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); if (s_con) { - id = nm_setting_connection_get_id (s_con); - uuid = nm_setting_connection_get_uuid (s_con); - con_type = nm_setting_connection_get_connection_type (s_con); - print_table_line (0, con_type, 17, uuid, 38, id, 0, NULL); + /* Obtain field values */ + timestamp = nm_setting_connection_get_timestamp (s_con); + timestamp_str = g_strdup_printf ("%ld", timestamp); + strftime (timestamp_real_str, sizeof (timestamp_real_str), "%c", localtime ((time_t *) ×tamp)); + nmc->allowed_fields[0].value = nm_setting_connection_get_id (s_con); + nmc->allowed_fields[1].value = nm_setting_connection_get_uuid (s_con); + nmc->allowed_fields[2].value = nm_setting_connection_get_connection_type (s_con); + nmc->allowed_fields[3].value = nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_SYSTEM ? _("system") : _("user"); + nmc->allowed_fields[4].value = timestamp_str; + nmc->allowed_fields[5].value = timestamp ? timestamp_real_str : _("never"); + nmc->allowed_fields[6].value = nm_setting_connection_get_autoconnect (s_con) ? _("yes") : _("no"); + nmc->allowed_fields[7].value = nm_setting_connection_get_read_only (s_con) ? _("yes") : _("no"); + + nmc->print_fields.flags &= ~NMC_PF_FLAG_HEADER; /* Clear HEADER flag */ + print_fields (nmc->print_fields, nmc->allowed_fields); + + g_free (timestamp_str); } } @@ -148,24 +193,46 @@ find_connection (GSList *list, const char *filter_type, const char *filter_val) static NMCResultCode do_connections_list (NmCli *nmc, int argc, char **argv) { + GError *error = NULL; + char *fields_str; + char *fields_all = NMC_FIELDS_CON_LIST_ALL; + char *fields_common = NMC_FIELDS_CON_LIST_COMMON; + guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0; + guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0; + guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0; gboolean valid_param_specified = FALSE; nmc->should_wait = FALSE; + 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) + fields_str = fields_all; + else + fields_str = nmc->required_fields; + + nmc->allowed_fields = nmc_fields_con_list; + nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error); + + if (error) { + g_string_printf (nmc->return_text, error->message); + g_error_free (error); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + goto error; + } + if (argc == 0) { valid_param_specified = TRUE; - if (nmc->print_output == NMC_PRINT_PRETTY) - print_table_header (_("Connections"), _("Type"), 17, _("UUID"), 38, _("Name"), 20, NULL); - else if (nmc->print_output == NMC_PRINT_NORMAL) - print_table_line (0, _("Type"), 17, _("UUID"), 38, _("Name"), 0, NULL); - if (nmc->print_output > NMC_PRINT_TERSE) - printf (_("System connections:\n")); - g_slist_foreach (nmc->system_connections, (GFunc) show_connection, NULL); + nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_HEADER; + nmc->print_fields.header_name = _("System connections"); + print_fields (nmc->print_fields, nmc->allowed_fields); + g_slist_foreach (nmc->system_connections, (GFunc) show_connection, nmc); - if (nmc->print_output > NMC_PRINT_TERSE) - printf (_("User connections:\n")); - g_slist_foreach (nmc->user_connections, (GFunc) show_connection, NULL); + nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_HEADER; + nmc->print_fields.header_name = _("User connections"); + print_fields (nmc->print_fields, nmc->allowed_fields); + g_slist_foreach (nmc->user_connections, (GFunc) show_connection, nmc); } else { while (argc > 0) { @@ -189,24 +256,25 @@ do_connections_list (NmCli *nmc, int argc, char **argv) g_string_printf (nmc->return_text, _("Error: %s - no such connection."), *argv); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; } + break; } else if (strcmp (*argv, "system") == 0) { valid_param_specified = TRUE; - if (nmc->print_output == NMC_PRINT_PRETTY) - print_table_header (_("System-wide connections"), _("Type"), 17, _("UUID"), 38, _("Name"), 20, NULL); - else if (nmc->print_output == NMC_PRINT_NORMAL) - print_table_line (0, _("Type"), 17, _("UUID"), 38, _("Name"), 0, NULL); - g_slist_foreach (nmc->system_connections, (GFunc) show_connection, NULL); + nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_HEADER; + nmc->print_fields.header_name = _("System connections"); + print_fields (nmc->print_fields, nmc->allowed_fields); + g_slist_foreach (nmc->system_connections, (GFunc) show_connection, nmc); + break; } else if (strcmp (*argv, "user") == 0) { valid_param_specified = TRUE; - if (nmc->print_output == NMC_PRINT_PRETTY) - print_table_header (_("User connections"), _("Type"), 17, _("UUID"), 38, _("Name"), 20, NULL); - else if (nmc->print_output == NMC_PRINT_NORMAL) - print_table_line (0, _("Type"), 17, _("UUID"), 38, _("Name"), 0, NULL); - g_slist_foreach (nmc->user_connections, (GFunc) show_connection, NULL); + nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_HEADER; + nmc->print_fields.header_name = _("User connections"); + print_fields (nmc->print_fields, nmc->allowed_fields); + g_slist_foreach (nmc->user_connections, (GFunc) show_connection, nmc); + break; } else { fprintf (stderr, _("Unknown parameter: %s\n"), *argv); @@ -226,12 +294,17 @@ error: return nmc->return_value; } +typedef struct { + NmCli *nmc; + NMConnectionScope scope; +} StatusInfo; + static void show_active_connection (gpointer data, gpointer user_data) { NMActiveConnection *active = NM_ACTIVE_CONNECTION (data); - GSList *con_list = (GSList *) user_data; - GSList *iter; + StatusInfo *info = (StatusInfo *) user_data; + GSList *con_list, *iter; const char *active_path; NMConnectionScope active_service_scope; NMSettingConnection *s_con; @@ -239,12 +312,14 @@ show_active_connection (gpointer data, gpointer user_data) GString *dev_str; int i; - dev_str = g_string_new (NULL); - active_path = nm_active_connection_get_connection (active); active_service_scope = nm_active_connection_get_scope (active); + if (active_service_scope != info->scope) + return; + /* Get devices of the active connection */ + dev_str = g_string_new (NULL); devices = nm_active_connection_get_devices (active); for (i = 0; devices && (i < devices->len); i++) { NMDevice *device = g_ptr_array_index (devices, i); @@ -255,24 +330,29 @@ show_active_connection (gpointer data, gpointer user_data) if (dev_str->len > 0) g_string_truncate (dev_str, dev_str->len - 1); /* Cut off last ',' */ + con_list = (info->scope == NM_CONNECTION_SCOPE_SYSTEM) ? info->nmc->system_connections : info->nmc->user_connections; for (iter = con_list; iter; iter = g_slist_next (iter)) { NMConnection *connection = (NMConnection *) iter->data; const char *con_path = nm_connection_get_path (connection); - NMConnectionScope con_scope = nm_connection_get_scope (connection); - if (!strcmp (active_path, con_path) && active_service_scope == con_scope) { - /* this connection is active */ + if (!strcmp (active_path, con_path)) { + /* This connection is active */ s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); g_assert (s_con != NULL); - // FIXME: Fix the output - print_table_line (0, nm_active_connection_get_default (active) ? _("yes") : _("no"), 8, - nm_active_connection_get_service_name (active), 45, -// nm_active_connection_get_specific_object (active), 0, -// nm_active_connection_get_connection (active), 0, - dev_str->str, 10, - nm_setting_connection_get_uuid (s_con), 38, - nm_setting_connection_get_id (s_con), 0, NULL); + /* Obtain field values */ + info->nmc->allowed_fields[0].value = nm_setting_connection_get_id (s_con); + info->nmc->allowed_fields[1].value = nm_setting_connection_get_uuid (s_con); + info->nmc->allowed_fields[2].value = dev_str->str; + info->nmc->allowed_fields[3].value = active_service_scope == NM_CONNECTION_SCOPE_SYSTEM ? _("system") : _("user"); + info->nmc->allowed_fields[4].value = nm_active_connection_get_default (active) ? _("yes") : _("no"); + info->nmc->allowed_fields[5].value = nm_active_connection_get_service_name (active); + info->nmc->allowed_fields[6].value = nm_active_connection_get_specific_object (active); + info->nmc->allowed_fields[7].value = NM_IS_VPN_CONNECTION (active) ? _("yes") : _("no"); + + info->nmc->print_fields.flags &= ~NMC_PF_FLAG_HEADER; /* Clear HEADER flag */ + print_fields (info->nmc->print_fields, info->nmc->allowed_fields); + break; } } @@ -283,6 +363,14 @@ static NMCResultCode do_connections_status (NmCli *nmc, int argc, char **argv) { const GPtrArray *active_cons; + GError *error = NULL; + StatusInfo *info; + char *fields_str; + char *fields_all = NMC_FIELDS_CON_STATUS_ALL; + char *fields_common = NMC_FIELDS_CON_STATUS_COMMON; + guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0; + guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0; + guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0; nmc->should_wait = FALSE; @@ -292,18 +380,40 @@ do_connections_status (NmCli *nmc, int argc, char **argv) active_cons = nm_client_get_active_connections (nmc->client); - // FIXME: Fix the output - if (nmc->print_output == NMC_PRINT_PRETTY) - print_table_header (_("Active connections"), _("Default"), 8, _("Service"), 45, _("Devices"), 10, _("UUID"), 38, _("Name"), 20, NULL); - else if (nmc->print_output == NMC_PRINT_NORMAL) - print_table_line (0, _("Default"), 8, _("Service"), 45, _("Devices"), 10, _("UUID"), 38, _("Name"), 0, NULL); + 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) + fields_str = fields_all; + else + fields_str = nmc->required_fields; - if (active_cons && active_cons->len) { - g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) nmc->system_connections); - g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) nmc->user_connections); + nmc->allowed_fields = nmc_fields_con_status; + nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error); + + if (error) { + g_string_printf (nmc->return_text, error->message); + g_error_free (error); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + goto error; } - return NMC_RESULT_SUCCESS; + nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_HEADER; + nmc->print_fields.header_name = _("Active connections"); + print_fields (nmc->print_fields, nmc->allowed_fields); + + if (active_cons && active_cons->len) { + info = g_malloc0 (sizeof (StatusInfo)); + info->nmc = nmc; + info->scope = NM_CONNECTION_SCOPE_SYSTEM; + g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) info); + info->scope = NM_CONNECTION_SCOPE_USER; + g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) info); + g_free (info); + } + +error: + + return nmc->return_value; } /* -------------------- diff --git a/cli/src/devices.c b/cli/src/devices.c index d6c0b43dc5..1be00d9c45 100644 --- a/cli/src/devices.c +++ b/cli/src/devices.c @@ -55,6 +55,35 @@ #include "devices.h" +/* Available field for 'dev status' */ +static NmcOutputField nmc_fields_dev_status[] = { + {"DEVICE", N_("DEVICE"), 10, NULL, 0}, /* 0 */ + {"TYPE", N_("TYPE"), 17, NULL, 0}, /* 1 */ + {"STATE", N_("STATE"), 12, NULL, 0}, /* 2 */ + {NULL, NULL, 0, NULL, 0} +}; +#define NMC_FIELDS_DEV_STATUS_ALL "DEVICE,TYPE,STATE" +#define NMC_FIELDS_DEV_STATUS_COMMON "DEVICE,TYPE,STATE" + +/* Available field for 'dev wifi list' */ +static NmcOutputField nmc_fields_dev_wifi_list[] = { + {"SSID", N_("SSID"), 33, NULL, 0}, /* 0 */ + {"BSSID", N_("BSSID"), 19, NULL, 0}, /* 1 */ + {"MODE", N_("MODE"), 16, NULL, 0}, /* 2 */ + {"FREQ", N_("FREQ"), 10, NULL, 0}, /* 3 */ + {"RATE", N_("RATE"), 10, NULL, 0}, /* 4 */ + {"SIGNAL", N_("SIGNAL"), 8, NULL, 0}, /* 5 */ + {"SECURITY", N_("SECURITY"), 10, NULL, 0}, /* 6 */ + {"WPA-FLAGS", N_("WPA-FLAGS"), 25, NULL, 0}, /* 7 */ + {"RSN-FLAGS", N_("RSN-FLAGS"), 25, NULL, 0}, /* 8 */ + {"DEVICE", N_("DEVICE"), 10, NULL, 0}, /* 9 */ + {"ACTIVE", N_("ACTIVE"), 8, NULL, 0}, /* 10 */ + {NULL, NULL, 0, NULL, 0} +}; +#define NMC_FIELDS_DEV_WIFI_LIST_ALL "SSID,BSSID,MODE,FREQ,RATE,SIGNAL,SECURITY,WPA-FLAGS,RSN-FLAGS,DEVICE,ACTIVE" +#define NMC_FIELDS_DEV_WIFI_LIST_COMMON "SSID,BSSID,MODE,FREQ,RATE,SIGNAL,SECURITY,ACTIVE" + + /* static function prototypes */ static void usage (void); static const char *device_state_to_string (NMDeviceState state); @@ -75,7 +104,7 @@ usage (void) " status\n" " list [iface ]\n" " disconnect iface [--nowait] [--timeout ]\n" - " wifi [list [iface ] | apinfo iface hwaddr ]\n\n")); + " wifi [list [iface ] [hwaddr ]]\n\n")); } /* quit main loop */ @@ -212,63 +241,94 @@ ip4_address_as_string (guint32 ip) } } +typedef struct { + NmCli *nmc; + const char* active_bssid; + const char* device; +} APInfo; + static void detail_access_point (gpointer data, gpointer user_data) { NMAccessPoint *ap = NM_ACCESS_POINT (data); - const char *active_bssid = (const char *) user_data; - GString *str; + APInfo *info = (APInfo *) user_data; gboolean active = FALSE; - guint32 flags, wpa_flags, rsn_flags; - const GByteArray * ssid; - char *tmp; + guint32 flags, wpa_flags, rsn_flags, freq, bitrate; + guint8 strength; + const GByteArray *ssid; + const char *hwaddr; + NM80211Mode mode; + char *freq_str, *ssid_str, *bitrate_str, *strength_str, *wpa_flags_str, *rsn_flags_str; + GString *security_str; - flags = nm_access_point_get_flags (ap); - wpa_flags = nm_access_point_get_wpa_flags (ap); - rsn_flags = nm_access_point_get_rsn_flags (ap); - - if (active_bssid) { + if (info->active_bssid) { const char *current_bssid = nm_access_point_get_hw_address (ap); - if (current_bssid && !strcmp (current_bssid, active_bssid)) + if (current_bssid && !strcmp (current_bssid, info->active_bssid)) active = TRUE; } - str = g_string_new (NULL); - g_string_append_printf (str, - _("%s, %s, Freq %d MHz, Rate %d Mb/s, Strength %d"), - (nm_access_point_get_mode (ap) == NM_802_11_MODE_INFRA) ? ("Infra") : _("Ad-Hoc"), - nm_access_point_get_hw_address (ap), - nm_access_point_get_frequency (ap), - nm_access_point_get_max_bitrate (ap) / 1000, - nm_access_point_get_strength (ap)); + /* Get AP properties */ + flags = nm_access_point_get_flags (ap); + wpa_flags = nm_access_point_get_wpa_flags (ap); + rsn_flags = nm_access_point_get_rsn_flags (ap); + ssid = nm_access_point_get_ssid (ap); + hwaddr = nm_access_point_get_hw_address (ap); + freq = nm_access_point_get_frequency (ap); + mode = nm_access_point_get_mode (ap); + bitrate = nm_access_point_get_max_bitrate (ap); + strength = nm_access_point_get_strength (ap); + /* Convert to strings */ + ssid_str = g_strdup_printf ("%s", ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : _("(none)")); + freq_str = g_strdup_printf (_("%u MHz"), freq); + bitrate_str = g_strdup_printf (_("%u MB/s"), bitrate/1000); + strength_str = g_strdup_printf ("%u", strength); + wpa_flags_str = ap_wpa_rsn_flags_to_string (wpa_flags); + rsn_flags_str = ap_wpa_rsn_flags_to_string (rsn_flags); + + security_str = g_string_new (NULL); if ( !(flags & NM_802_11_AP_FLAGS_PRIVACY) && (wpa_flags != NM_802_11_AP_SEC_NONE) && (rsn_flags != NM_802_11_AP_SEC_NONE)) - g_string_append (str, _(", Encrypted: ")); + g_string_append (security_str, _("Encrypted: ")); if ( (flags & NM_802_11_AP_FLAGS_PRIVACY) && (wpa_flags == NM_802_11_AP_SEC_NONE) && (rsn_flags == NM_802_11_AP_SEC_NONE)) - g_string_append (str, _(" WEP")); + g_string_append (security_str, _("WEP ")); if (wpa_flags != NM_802_11_AP_SEC_NONE) - g_string_append (str, _(" WPA")); + g_string_append (security_str, _("WPA ")); if (rsn_flags != NM_802_11_AP_SEC_NONE) - g_string_append (str, _(" WPA2")); + g_string_append (security_str, _("WPA2 ")); if ( (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) - g_string_append (str, _(" Enterprise")); + g_string_append (security_str, _("Enterprise ")); - /* FIXME: broadcast/hidden */ + if (security_str->len > 0) + g_string_truncate (security_str, security_str->len-1); /* Chop off last space */ - ssid = nm_access_point_get_ssid (ap); - tmp = g_strdup_printf (" %s%s", active ? "*" : "", - ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : _("(none)")); + info->nmc->allowed_fields[0].value = ssid_str; + info->nmc->allowed_fields[1].value = hwaddr; + info->nmc->allowed_fields[2].value = mode == NM_802_11_MODE_ADHOC ? _("Ad-Hoc") : mode == NM_802_11_MODE_INFRA ? _("Infrastructure") : _("Unknown"); + info->nmc->allowed_fields[3].value = freq_str; + info->nmc->allowed_fields[4].value = bitrate_str; + info->nmc->allowed_fields[5].value = strength_str; + info->nmc->allowed_fields[6].value = security_str->str; + info->nmc->allowed_fields[7].value = wpa_flags_str; + info->nmc->allowed_fields[8].value = rsn_flags_str; + info->nmc->allowed_fields[9].value = info->device; + info->nmc->allowed_fields[10].value = active ? _("yes") : _("no"); - print_table_line (0, tmp, 25, str->str, 0, NULL); + info->nmc->print_fields.flags &= ~NMC_PF_FLAG_HEADER; /* Clear HEADER flag */ + print_fields (info->nmc->print_fields, info->nmc->allowed_fields); - g_string_free (str, TRUE); - g_free (tmp); + g_free (ssid_str); + g_free (freq_str); + g_free (bitrate_str); + g_free (strength_str); + g_free (wpa_flags_str); + g_free (rsn_flags_str); + g_string_free (security_str, TRUE); } struct cb_info { @@ -280,7 +340,8 @@ static void show_device_info (gpointer data, gpointer user_data) { NMDevice *device = NM_DEVICE (data); -// struct cb_info *info = user_data; + NmCli *nmc = (NmCli *) user_data; + APInfo *info; char *tmp; NMDeviceState state; const char *dev_type; @@ -365,11 +426,21 @@ show_device_info (gpointer data, gpointer user_data) active_bssid = active_ap ? nm_access_point_get_hw_address (active_ap) : NULL; } - printf (_("\n Wireless Access Points %s\n"), active_ap ? _("(* = current AP)") : ""); + printf (_("\n Wireless Access Points\n")); + nmc->print_fields.flags = NMC_PF_FLAG_HEADER; + nmc->print_fields.indent = 2; /* Indent by 2 spaces */ + nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_WIFI_LIST_COMMON, nmc->allowed_fields, NULL); + print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */ + + info = g_malloc0 (sizeof (APInfo)); + info->nmc = nmc; + info->active_bssid = active_bssid; + info->device = nm_device_get_iface (device); aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device)); if (aps && aps->len) - g_ptr_array_foreach ((GPtrArray *) aps, detail_access_point, (gpointer) active_bssid); + g_ptr_array_foreach ((GPtrArray *) aps, detail_access_point, (gpointer) info); + g_free (info); } else if (NM_IS_DEVICE_ETHERNET (device)) { printf (_("\n Wired Properties\n")); @@ -425,22 +496,26 @@ show_device_info (gpointer data, gpointer user_data) static void show_device_status (NMDevice *device, NmCli *nmc) { - const char *iface; - const char *type; - const char *state; + nmc->allowed_fields[0].value = nm_device_get_iface (device); + nmc->allowed_fields[1].value = get_device_type (device); + nmc->allowed_fields[2].value = device_state_to_string (nm_device_get_state (device)); - iface = nm_device_get_iface (device); - type = get_device_type (device); - state = device_state_to_string (nm_device_get_state (device)); - - print_table_line (0, iface, 10, type, 17, state, 0, NULL); + nmc->print_fields.flags &= ~NMC_PF_FLAG_HEADER; /* Clear HEADER flag */ + print_fields (nmc->print_fields, nmc->allowed_fields); } static NMCResultCode do_devices_status (NmCli *nmc, int argc, char **argv) { + GError *error = NULL; const GPtrArray *devices; int i; + char *fields_str; + char *fields_all = NMC_FIELDS_DEV_STATUS_ALL; + char *fields_common = NMC_FIELDS_DEV_STATUS_COMMON; + guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0; + guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0; + guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0; while (argc > 0) { fprintf (stderr, _("Unknown parameter: %s\n"), *argv); @@ -454,10 +529,26 @@ do_devices_status (NmCli *nmc, int argc, char **argv) devices = nm_client_get_devices (nmc->client); - if (nmc->print_output == NMC_PRINT_PRETTY) - print_table_header (_("Status of devices"), _("Device"), 10, _("Type"), 17, _("State"), 12, NULL); - else if (nmc->print_output == NMC_PRINT_NORMAL) - print_table_line (0, _("Device"), 10, _("Type"), 17, _("State"), 0, NULL); + 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) + fields_str = fields_all; + else + fields_str = nmc->required_fields; + + nmc->allowed_fields = nmc_fields_dev_status; + nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error); + + if (error) { + g_string_printf (nmc->return_text, error->message); + g_error_free (error); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + goto error; + } + + nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_HEADER; + nmc->print_fields.header_name = _("Status of devices"); + print_fields (nmc->print_fields, nmc->allowed_fields); for (i = 0; devices && (i < devices->len); i++) { NMDevice *device = g_ptr_array_index (devices, i); @@ -504,6 +595,9 @@ do_devices_list (NmCli *nmc, int argc, char **argv) devices = nm_client_get_devices (nmc->client); + /* Set allowed fields for use while printing in detail_access_point() */ + nmc->allowed_fields = nmc_fields_dev_wifi_list; + if (iface_specified) { for (i = 0; devices && (i < devices->len); i++) { NMDevice *candidate = g_ptr_array_index (devices, i); @@ -517,10 +611,10 @@ do_devices_list (NmCli *nmc, int argc, char **argv) nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; goto error; } - show_device_info (device, nmc->client); + show_device_info (device, nmc); } else { if (devices) - g_ptr_array_foreach ((GPtrArray *) devices, show_device_info, nmc->client); + g_ptr_array_foreach ((GPtrArray *) devices, show_device_info, nmc); } error: @@ -665,119 +759,46 @@ error: } static void -show_acces_point_info (NMDevice *device) +show_acces_point_info (NMDevice *device, NmCli *nmc) { NMAccessPoint *active_ap = NULL; const char *active_bssid = NULL; const GPtrArray *aps; + APInfo *info; if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { active_ap = nm_device_wifi_get_active_access_point (NM_DEVICE_WIFI (device)); active_bssid = active_ap ? nm_access_point_get_hw_address (active_ap) : NULL; } + info = g_malloc0 (sizeof (APInfo)); + info->nmc = nmc; + info->active_bssid = active_bssid; + info->device = nm_device_get_iface (device); aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device)); if (aps && aps->len) - g_ptr_array_foreach ((GPtrArray *) aps, detail_access_point, (gpointer) active_bssid); + g_ptr_array_foreach ((GPtrArray *) aps, detail_access_point, (gpointer) info); + g_free (info); } static NMCResultCode do_device_wifi_list (NmCli *nmc, int argc, char **argv) { - //TODO: cleanup - const GPtrArray *devices; + GError *error = NULL; NMDevice *device = NULL; - const char *iface = NULL; - gboolean iface_specified = FALSE; - int i; - - while (argc > 0) { - if (strcmp (*argv, "iface") == 0) { - iface_specified = TRUE; - - if (next_arg (&argc, &argv) != 0) { - g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto error; - } - - iface = *argv; - } else { - fprintf (stderr, _("Unknown parameter: %s\n"), *argv); - } - - argc--; - argv++; - } - - /* create NMClient */ - if (!nmc->get_client (nmc)) - goto error; - - devices = nm_client_get_devices (nmc->client); - - if (iface_specified) { - for (i = 0; devices && (i < devices->len); i++) { - NMDevice *candidate = g_ptr_array_index (devices, i); - const char *dev_iface = nm_device_get_iface (candidate); - - if (!strcmp (dev_iface, iface)) - device = candidate; - } - - if (!device) { - g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto error; - } - - if ((NM_IS_DEVICE_WIFI (device))) { - if (nmc->print_output == NMC_PRINT_PRETTY) - print_table_header (_("WiFi scan list"), NULL); - - show_acces_point_info (device); - } else { - g_string_printf (nmc->return_text, _("Error: Device '%s' is not a WiFi device."), iface); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto error; - } - } else { - if (nmc->print_output == NMC_PRINT_PRETTY) - print_table_header (_("WiFi scan list"), NULL); - - for (i = 0; devices && (i < devices->len); i++) { - NMDevice *dev = g_ptr_array_index (devices, i); - const char *dev_iface = nm_device_get_iface (dev); - - if ((NM_IS_DEVICE_WIFI (dev))) { - if (nmc->print_output > NMC_PRINT_TERSE) - print_table_line (0, _("Device:"), 0, dev_iface, 0, NULL); - - show_acces_point_info (dev); - } - } - } - -error: - return nmc->return_value; -} - -static NMCResultCode -do_device_wifi_apinfo (NmCli *nmc, int argc, char **argv) -{ - const GPtrArray *devices; - const GPtrArray *aps; NMAccessPoint *ap = NULL; const char *iface = NULL; const char *hwaddr_user = NULL; - const char *hwaddr; - gboolean stop = FALSE; - guint32 flags, wpa_flags, rsn_flags, freq, bitrate; - guint8 strength; - const GByteArray *ssid; - NM80211Mode mode; - char *freq_str, *ssid_str, *bitrate_str, *strength_str, *wpa_flags_str, *rsn_flags_str; + const GPtrArray *devices; + const GPtrArray *aps; + APInfo *info; int i, j; + char *fields_str; + char *fields_all = NMC_FIELDS_DEV_WIFI_LIST_ALL; + char *fields_common = NMC_FIELDS_DEV_WIFI_LIST_COMMON; + guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0; + guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0; + guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0; while (argc > 0) { if (strcmp (*argv, "iface") == 0) { @@ -802,90 +823,129 @@ do_device_wifi_apinfo (NmCli *nmc, int argc, char **argv) argv++; } - if (!hwaddr_user) { - g_string_printf (nmc->return_text, _("Error: hwaddr has to be specified.")); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto error; - } - /* create NMClient */ if (!nmc->get_client (nmc)) goto error; devices = nm_client_get_devices (nmc->client); - for (i = 0; !stop && devices && (i < devices->len); i++) { - NMDevice *device = g_ptr_array_index (devices, i); - const char *dev_iface = nm_device_get_iface (device); + 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) + fields_str = fields_all; + else + fields_str = nmc->required_fields; - if (iface) { - if (!strcmp (iface, dev_iface)) - stop = TRUE; - else - continue; - } + nmc->allowed_fields = nmc_fields_dev_wifi_list; + nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error); - aps = NULL; - if ((NM_IS_DEVICE_WIFI (device))) - aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device)); - for (j = 0; aps && (j < aps->len); j++) { - char *hwaddr_up; - NMAccessPoint *candidate_ap = g_ptr_array_index (aps, j); - const char *candidate_hwaddr = nm_access_point_get_hw_address (candidate_ap); - - hwaddr_up = g_ascii_strup (hwaddr_user, -1); - if (!strcmp (hwaddr_up, candidate_hwaddr)) - ap = candidate_ap; - g_free (hwaddr_up); - } - } - - if (!ap) { - g_string_printf (nmc->return_text, _("Error: Access point with hwaddr '%s' not found."), hwaddr_user); + if (error) { + g_string_printf (nmc->return_text, error->message); + g_error_free (error); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; goto error; } - /* get AP properties */ - flags = nm_access_point_get_flags (ap); - wpa_flags = nm_access_point_get_wpa_flags (ap); - rsn_flags = nm_access_point_get_rsn_flags (ap); - ssid = nm_access_point_get_ssid (ap); - hwaddr = nm_access_point_get_hw_address (ap); - freq = nm_access_point_get_frequency (ap); - mode = nm_access_point_get_mode (ap); - bitrate = nm_access_point_get_max_bitrate (ap); - strength = nm_access_point_get_strength (ap); + nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_HEADER; + nmc->print_fields.header_name = _("WiFi scan list"); - /* print them */ - ssid_str = g_strdup_printf ("%s", ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : _("(none)")); - freq_str = g_strdup_printf (_("%u MHz"), freq); - bitrate_str = g_strdup_printf (_("%u MB/s"), bitrate/1000); - strength_str = g_strdup_printf ("%u", strength); - wpa_flags_str = ap_wpa_rsn_flags_to_string (wpa_flags); - rsn_flags_str = ap_wpa_rsn_flags_to_string (rsn_flags); + if (iface) { + /* Device specified - list only APs of this interface */ + for (i = 0; devices && (i < devices->len); i++) { + NMDevice *candidate = g_ptr_array_index (devices, i); + const char *dev_iface = nm_device_get_iface (candidate); - if (nmc->print_output == NMC_PRINT_PRETTY) - print_table_header (_("AP parameters"), NULL); - else if (nmc->print_output == NMC_PRINT_NORMAL) - print_table_line (0, _("AP parameters"), 0, NULL); + if (!strcmp (dev_iface, iface)) { + device = candidate; + break; + } + } - print_table_line (0, _("SSID:"), 25, ssid_str, 0, NULL); - print_table_line (0, _("BSSID:"), 25, hwaddr, 0, NULL); - print_table_line (0, _("Frequency:"), 25, freq_str, 0, NULL); - print_table_line (0, _("Mode:"), 25, mode == NM_802_11_MODE_ADHOC ? _("Ad-hoc") : mode == NM_802_11_MODE_INFRA ? _("Infrastructure") : _("Unknown"), 0, NULL); - print_table_line (0, _("Maximal bitrate:"), 25, bitrate_str, 0, NULL); - print_table_line (0, _("Strength:"), 25, strength_str, 0, NULL); - print_table_line (0, _("Flags:"), 25, flags == NM_802_11_AP_FLAGS_PRIVACY ? _("privacy") : _("(none)"), 0, NULL); - print_table_line (0, _("WPA flags:"), 25, wpa_flags_str, 0, NULL); - print_table_line (0, _("RSN flags:"), 25, rsn_flags_str, 0, NULL); + if (!device) { + g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + goto error; + } - g_free (ssid_str); - g_free (freq_str); - g_free (bitrate_str); - g_free (strength_str); - g_free (wpa_flags_str); - g_free (rsn_flags_str); + if (NM_IS_DEVICE_WIFI (device)) { + if (hwaddr_user) { + /* Specific AP requested - list only that */ + aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device)); + for (j = 0; aps && (j < aps->len); j++) { + char *hwaddr_up; + NMAccessPoint *candidate_ap = g_ptr_array_index (aps, j); + const char *candidate_hwaddr = nm_access_point_get_hw_address (candidate_ap); + + hwaddr_up = g_ascii_strup (hwaddr_user, -1); + if (!strcmp (hwaddr_up, candidate_hwaddr)) + ap = candidate_ap; + g_free (hwaddr_up); + } + if (!ap) { + g_string_printf (nmc->return_text, _("Error: Access point with hwaddr '%s' not found."), hwaddr_user); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + goto error; + } + info = g_malloc0 (sizeof (APInfo)); + info->nmc = nmc; + info->active_bssid = NULL; + info->device = nm_device_get_iface (device); + print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */ + detail_access_point (ap, info); + g_free (info); + } else { + print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */ + show_acces_point_info (device, nmc); + } + } else { + g_string_printf (nmc->return_text, _("Error: Device '%s' is not a WiFi device."), iface); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + goto error; + } + } else { + /* List APs for all devices */ + print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */ + if (hwaddr_user) { + /* Specific AP requested - list only that */ + for (i = 0; devices && (i < devices->len); i++) { + NMDevice *dev = g_ptr_array_index (devices, i); + + if (!NM_IS_DEVICE_WIFI (dev)) + continue; + + aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (dev)); + for (j = 0; aps && (j < aps->len); j++) { + char *hwaddr_up; + NMAccessPoint *candidate_ap = g_ptr_array_index (aps, j); + const char *candidate_hwaddr = nm_access_point_get_hw_address (candidate_ap); + + hwaddr_up = g_ascii_strup (hwaddr_user, -1); + if (!strcmp (hwaddr_up, candidate_hwaddr)) { + ap = candidate_ap; + + info = g_malloc0 (sizeof (APInfo)); + info->nmc = nmc; + info->active_bssid = NULL; + info->device = nm_device_get_iface (dev); + detail_access_point (ap, info); + g_free (info); + } + g_free (hwaddr_up); + } + } + if (!ap) { + g_string_printf (nmc->return_text, _("Error: Access point with hwaddr '%s' not found."), hwaddr_user); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + goto error; + } + } else { + for (i = 0; devices && (i < devices->len); i++) { + NMDevice *dev = g_ptr_array_index (devices, i); + if (NM_IS_DEVICE_WIFI (dev)) + show_acces_point_info (dev, nmc); + } + } + } error: return nmc->return_value; @@ -900,9 +960,6 @@ do_device_wifi (NmCli *nmc, int argc, char **argv) if (matches (*argv, "list") == 0) { nmc->return_value = do_device_wifi_list (nmc, argc-1, argv+1); } - else if (matches (*argv, "apinfo") == 0) { - nmc->return_value = do_device_wifi_apinfo (nmc, argc-1, argv+1); - } else { g_string_printf (nmc->return_text, _("Error: 'dev wifi' command '%s' is not valid."), *argv); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; diff --git a/cli/src/nmcli.c b/cli/src/nmcli.c index f2ed7156b0..ad793406fb 100644 --- a/cli/src/nmcli.c +++ b/cli/src/nmcli.c @@ -45,7 +45,7 @@ #include "devices.h" #include "network-manager.h" -#define NMCLI_VERSION "0.1" +#define NMCLI_VERSION "0.2" typedef struct { @@ -64,10 +64,13 @@ usage (const char *prog_name) fprintf (stderr, _("Usage: %s [OPTIONS] OBJECT { COMMAND | help }\n\n" "OPTIONS\n" - " -t[erse] terse output\n" - " -p[retty] pretty output\n" - " -v[ersion] show program version\n" - " -h[elp] print this help\n\n" + " -t[erse] terse output\n" + " -p[retty] pretty output\n" + " -m[ultiline] multiline output\n" + " -f[ields] |all|common specify fields to output\n" + " -e[scape] yes|no escape columns separators in values\n" + " -v[ersion] show program version\n" + " -h[elp] print this help\n\n" "OBJECT\n" " nm NetworkManager status\n" " con NetworkManager connections\n" @@ -132,9 +135,57 @@ parse_command_line (NmCli *nmc, int argc, char **argv) if (opt[1] == '-') opt++; if (matches (opt, "-terse") == 0) { - nmc->print_output = NMC_PRINT_TERSE; + if (nmc->print_output == NMC_PRINT_TERSE) { + g_string_printf (nmc->return_text, _("Option '--terse' is specified the second time.")); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return nmc->return_value; + } + else if (nmc->print_output == NMC_PRINT_PRETTY) { + g_string_printf (nmc->return_text, _("Option '--terse' is mutually exclusive with '--pretty'.")); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return nmc->return_value; + } + else + nmc->print_output = NMC_PRINT_TERSE; } else if (matches (opt, "-pretty") == 0) { - nmc->print_output = NMC_PRINT_PRETTY; + if (nmc->print_output == NMC_PRINT_PRETTY) { + g_string_printf (nmc->return_text, _("Option '--pretty' is specified the second time.")); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return nmc->return_value; + } + else if (nmc->print_output == NMC_PRINT_TERSE) { + g_string_printf (nmc->return_text, _("Option '--pretty' is mutually exclusive with '--terse'.")); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return nmc->return_value; + } + else + nmc->print_output = NMC_PRINT_PRETTY; + } else if (matches (opt, "-multiline") == 0) { + nmc->multiline_output = TRUE; + } else if (matches (opt, "-escape") == 0) { + next_arg (&argc, &argv); + if (argc <= 1) { + g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return nmc->return_value; + } + if (!strcmp (argv[1], "yes")) + nmc->escape_values = TRUE; + else if (!strcmp (argv[1], "no")) + nmc->escape_values = FALSE; + else { + g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[1], opt); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return nmc->return_value; + } + } else if (matches (opt, "-fields") == 0) { + next_arg (&argc, &argv); + if (argc <= 1) { + g_string_printf (nmc->return_text, _("Error: fields for '%s' options are missing."), opt); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return nmc->return_value; + } + nmc->required_fields = g_strdup (argv[1]); } else if (matches (opt, "-version") == 0) { printf (_("nmcli tool, version %s\n"), NMCLI_VERSION); return NMC_RESULT_SUCCESS; @@ -150,6 +201,20 @@ parse_command_line (NmCli *nmc, int argc, char **argv) argv++; } + /* Some validity options checks */ + if (nmc->print_output == NMC_PRINT_TERSE) { + if (!nmc->required_fields) { + g_string_printf (nmc->return_text, _("Option '--terse' requires specifying '--fields'.")); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return nmc->return_value; + } else if ( !strcasecmp (nmc->required_fields, "all") + || !strcasecmp (nmc->required_fields, "common")) { + g_string_printf (nmc->return_text, _("Option '--terse' requires specific '--fields' option, not 'all' or 'common'.")); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return nmc->return_value; + } + } + if (argc > 1) return do_cmd (nmc, argv[1], argc-1, argv+1); @@ -217,6 +282,11 @@ nmc_init (NmCli *nmc) nmc->should_wait = FALSE; nmc->print_output = NMC_PRINT_NORMAL; + nmc->multiline_output = FALSE; + nmc->escape_values = TRUE; + nmc->required_fields = NULL; + nmc->allowed_fields = NULL; + memset (&nmc->print_fields, '\0', sizeof (NmcPrintFields)); } static void @@ -231,6 +301,10 @@ nmc_cleanup (NmCli *nmc) g_slist_free (nmc->system_connections); g_slist_free (nmc->user_connections); + + g_free (nmc->required_fields); + if (nmc->print_fields.indices) + g_array_free (nmc->print_fields.indices, TRUE); } static gboolean diff --git a/cli/src/nmcli.h b/cli/src/nmcli.h index 2daa4154e6..8b4c34207e 100644 --- a/cli/src/nmcli.h +++ b/cli/src/nmcli.h @@ -20,10 +20,12 @@ #ifndef NMC_NMCLI_H #define NMC_NMCLI_H +#include + +#include #include #include - /* nmcli exit codes */ typedef enum { /* Indicates successful execution */ @@ -51,27 +53,55 @@ typedef enum { NMC_PRINT_PRETTY } NMCPrintOutput; +/* === Output fields === */ +typedef struct { + const char *name; /* Field's name */ + const char *name_l10n; /* Field's name for translation */ + int width; /* Width in screen columns */ + const char *value; /* Value of current field */ + guint32 flags; /* Flags */ +} NmcOutputField; + +/* Flags for NmcPrintFields */ +#define NMC_PF_FLAG_MULTILINE 0x00000001 /* Multiline output instead of tabular*/ +#define NMC_PF_FLAG_TERSE 0x00000002 /* Terse outpud mode */ +#define NMC_PF_FLAG_PRETTY 0x00000004 /* Pretty output mode */ +#define NMC_PF_FLAG_HEADER 0x00000008 /* Print headers instead of values */ +#define NMC_PF_FLAG_ESCAPE 0x00000010 /* Escape column separator and '\' */ + +typedef struct { + GArray *indices; /* Array of field indices to the array of allowed fields */ + char *header_name; /* Name of the output */ + int indent; /* Indent by this number of spaces */ + guint32 flags; /* Various flags for controlling output: see NMC_PF_FLAG_* values */ +} NmcPrintFields; + /* NmCli - main structure */ typedef struct _NmCli { - NMClient *client; - NMClient *(*get_client) (struct _NmCli *nmc); + NMClient *client; /* Pointer to NMClient of libnm-glib */ + NMClient *(*get_client) (struct _NmCli *nmc); /* Pointer to function for creating NMClient */ - NMCResultCode return_value; - GString *return_text; + NMCResultCode return_value; /* Return code of nmcli */ + GString *return_text; /* Reason text */ - int timeout; + int timeout; /* Operation timeout */ - NMRemoteSettingsSystem *system_settings; - NMRemoteSettings *user_settings; + NMRemoteSettingsSystem *system_settings; /* System settings */ + NMRemoteSettings *user_settings; /* User settings */ - gboolean system_settings_running; - gboolean user_settings_running; + gboolean system_settings_running; /* Is system settings service running? */ + gboolean user_settings_running; /* Is user settings service running? */ - GSList *system_connections; - GSList *user_connections; + GSList *system_connections; /* List of system connections */ + GSList *user_connections; /* List of user connections */ - gboolean should_wait; - NMCPrintOutput print_output; + gboolean should_wait; /* Indication that nmcli should not end yet */ + NMCPrintOutput print_output; /* Output mode */ + gboolean multiline_output; /* Multiline output instead of default tabular */ + gboolean escape_values; /* Whether to escape ':' and '\' in terse tabular mode */ + 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 */ } NmCli; #endif /* NMC_NMCLI_H */ diff --git a/cli/src/utils.c b/cli/src/utils.c index cd99b10fde..ce22947acb 100644 --- a/cli/src/utils.c +++ b/cli/src/utils.c @@ -21,6 +21,7 @@ #include #include +#include #include "utils.h" @@ -46,6 +47,171 @@ next_arg (int *argc, char ***argv) return 0; } +/* + * 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'. + */ +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")) + g_set_error (error, 0, 0, _("Error: 'con status': field '%s' has to be alone."), *iter); + + else + g_set_error (error, 0, 0, _("Error: 'con status': invalid field '%s'."), *iter); + g_array_free (array, TRUE); + array = NULL; + goto done; + } + } +done: + return array; +} + +void +print_fields (const NmcPrintFields fields, const NmcOutputField field_values[]) +{ + GString *str; + int width1, width2; + int table_width = 0; + char *line = NULL; + char *indent_str; + const char *value; + int i, idx; + gboolean multiline = fields.flags & NMC_PF_FLAG_MULTILINE; + gboolean terse = fields.flags & NMC_PF_FLAG_TERSE; + gboolean pretty = fields.flags & NMC_PF_FLAG_PRETTY; + gboolean header = fields.flags & NMC_PF_FLAG_HEADER; + gboolean escape = fields.flags & NMC_PF_FLAG_ESCAPE; + + /* Headers are not printed in terse mode */ + if (header && terse) + return; + + if (multiline) { + /* --- Multiline mode --- */ + if (header && pretty) { + /* Print the table header */ + table_width = g_utf8_strlen (fields.header_name, -1) + 4; + line = g_strnfill (79, '='); + width1 = strlen (fields.header_name); + width2 = g_utf8_strlen (fields.header_name, -1); + 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 */ + if (!header) { + for (i = 0; i < fields.indices->len; i++) { + char *tmp; + idx = g_array_index (fields.indices, int, i); + tmp = g_strdup_printf ("%s:", _(field_values[idx].name_l10n)); + printf ("%-*s%s\n", terse ? 0 : 20, tmp, field_values[idx].value); + g_free (tmp); + } + if (pretty) { + line = g_strnfill (79, '-'); + 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++) { + idx = g_array_index (fields.indices, int, i); + if (header) + value = _(field_values[idx].name_l10n); + else + value = field_values[idx].value; + 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++; + } + } + else + g_string_append_printf (str, "%s", value); + g_string_append_c (str, ':'); /* Column separator */ + } else { + width1 = strlen (value); + width2 = g_utf8_strlen (value, -1); /* Width of the string (in screen colums) */ + if (strlen (value) == 0) + value = "--"; + g_string_append_printf (str, "%-*s", field_values[idx].width + width1 - width2, value); + g_string_append_c (str, ' '); /* Column separator */ + table_width += field_values[idx].width + width1 - width2 + 1; + } + } + + if (table_width <= 0) + table_width = g_utf8_strlen (fields.header_name, -1) + 4; + + if (header && pretty) { + /* Print the table header */ + line = g_strnfill (table_width, '='); + width1 = strlen (fields.header_name); + width2 = g_utf8_strlen (fields.header_name, -1); + printf ("%s\n", line); + printf ("%*s\n", (table_width + width2)/2 + width1 - width2, fields.header_name); + printf ("%s\n", line); + g_free (line); + } + + + /* Print the line */ + if (str->len > 0) { + g_string_truncate (str, str->len-1); /* Chop off last column separator */ + if (fields.indent > 0) { + indent_str = g_strnfill (fields.indent, ' '); + g_string_prepend (str, indent_str); + g_free (indent_str); + } + printf ("%s\n", str->str); + } + + if (header && pretty) { + if (str->len > 0) { + line = g_strnfill (table_width, '-'); + printf ("%s\n", line); + g_free (line); + } + } + + g_string_free (str, TRUE); +} + + +/*--- obsolete printing functions ---*/ void print_table_header (const char *name, ...) { diff --git a/cli/src/utils.h b/cli/src/utils.h index 468550e212..513d214b83 100644 --- a/cli/src/utils.h +++ b/cli/src/utils.h @@ -20,8 +20,15 @@ #ifndef NMC_UTILS_H #define NMC_UTILS_H +#include + +#include "nmcli.h" + +/* === Functions === */ int matches (const char *cmd, const char *pattern); int next_arg (int *argc, char ***argv); +GArray *parse_output_fields (const char *fields_str, const NmcOutputField fields_array[], GError **error); +void print_fields (const NmcPrintFields fields, const NmcOutputField field_values[]); void print_table_header (const char *name, ...); void print_table_line (int indent, ...);