mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-15 20:45:32 +00:00
merge: cli pager
This commit is contained in:
commit
ae81216ae0
|
@ -796,8 +796,33 @@ nmc_active_connection_state_to_color (NMActiveConnectionState state, NMMetaTermC
|
|||
*color = NM_META_TERM_COLOR_RED;
|
||||
}
|
||||
|
||||
/* Essentially a version of nm_setting_connection_get_connection_type() that
|
||||
* prefers an alias instead of the settings name when in pretty print mode.
|
||||
* That is so that we print "wifi" instead of "802-11-wireless" in "nmcli c". */
|
||||
static const char *
|
||||
connection_type_pretty (const char *type, NMCPrintOutput print_output)
|
||||
{
|
||||
const NMMetaSettingInfoEditor *editor;
|
||||
int i;
|
||||
|
||||
if (print_output == NMC_PRINT_TERSE)
|
||||
return type;
|
||||
|
||||
for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) {
|
||||
editor = &nm_meta_setting_infos_editor[i];
|
||||
if (strcmp (type, editor->general->setting_name) == 0) {
|
||||
if (editor->alias)
|
||||
return editor->alias;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
static void
|
||||
fill_output_connection (NMConnection *connection, NMClient *client, GPtrArray *output_data, gboolean active_only)
|
||||
fill_output_connection (NMConnection *connection, NMClient *client, NMCPrintOutput print_output,
|
||||
GPtrArray *output_data, gboolean active_only)
|
||||
{
|
||||
NMSettingConnection *s_con;
|
||||
guint64 timestamp;
|
||||
|
@ -845,7 +870,7 @@ fill_output_connection (NMConnection *connection, NMClient *client, GPtrArray *o
|
|||
|
||||
set_val_strc (arr, 0, nm_setting_connection_get_id (s_con));
|
||||
set_val_strc (arr, 1, nm_setting_connection_get_uuid (s_con));
|
||||
set_val_strc (arr, 2, nm_setting_connection_get_connection_type (s_con));
|
||||
set_val_strc (arr, 2, connection_type_pretty (nm_setting_connection_get_connection_type (s_con), print_output));
|
||||
set_val_str (arr, 3, timestamp_str);
|
||||
set_val_str (arr, 4, timestamp ? timestamp_real_str : g_strdup (_("never")));
|
||||
set_val_strc (arr, 5, nm_setting_connection_get_autoconnect (s_con) ? _("yes") : _("no"));
|
||||
|
@ -862,7 +887,7 @@ fill_output_connection (NMConnection *connection, NMClient *client, GPtrArray *o
|
|||
}
|
||||
|
||||
static void
|
||||
fill_output_connection_for_invisible (NMActiveConnection *ac, GPtrArray *output_data)
|
||||
fill_output_connection_for_invisible (NMActiveConnection *ac, NMCPrintOutput print_output, GPtrArray *output_data)
|
||||
{
|
||||
NmcOutputField *arr;
|
||||
const char *ac_path = NULL;
|
||||
|
@ -878,7 +903,7 @@ fill_output_connection_for_invisible (NMActiveConnection *ac, GPtrArray *output_
|
|||
|
||||
set_val_str (arr, 0, name);
|
||||
set_val_strc (arr, 1, nm_active_connection_get_uuid (ac));
|
||||
set_val_strc (arr, 2, nm_active_connection_get_connection_type (ac));
|
||||
set_val_strc (arr, 2, connection_type_pretty (nm_active_connection_get_connection_type (ac), print_output));
|
||||
set_val_strc (arr, 3, NULL);
|
||||
set_val_strc (arr, 4, NULL);
|
||||
set_val_strc (arr, 5, NULL);
|
||||
|
@ -1696,14 +1721,14 @@ do_connections_show (NmCli *nmc, int argc, char **argv)
|
|||
* (e.g. private connections of a different user). Show them as well. */
|
||||
invisibles = get_invisible_active_connections (nmc);
|
||||
for (i = 0; i < invisibles->len; i++)
|
||||
fill_output_connection_for_invisible (invisibles->pdata[i], out.output_data);
|
||||
fill_output_connection_for_invisible (invisibles->pdata[i], nmc->nmc_config.print_output, out.output_data);
|
||||
g_ptr_array_free (invisibles, TRUE);
|
||||
|
||||
/* Sort the connections and fill the output data */
|
||||
connections = nm_client_get_connections (nmc->client);
|
||||
sorted_cons = sort_connections (connections, nmc, order);
|
||||
for (i = 0; i < sorted_cons->len; i++)
|
||||
fill_output_connection (sorted_cons->pdata[i], nmc->client, out.output_data, active_only);
|
||||
fill_output_connection (sorted_cons->pdata[i], nmc->client, nmc->nmc_config.print_output, out.output_data, active_only);
|
||||
g_ptr_array_free (sorted_cons, TRUE);
|
||||
|
||||
print_data_prepare_width (out.output_data);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright 2010 - 2015 Red Hat, Inc.
|
||||
* Copyright 2010 - 2017 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include "nm-default.h"
|
||||
|
@ -1296,6 +1296,9 @@ do_overview (NmCli *nmc, int argc, char **argv)
|
|||
/* Register polkit agent */
|
||||
nmc_start_polkit_agent_start_try (nmc);
|
||||
|
||||
/* Optionally start paging the output. */
|
||||
nmc_terminal_spawn_pager (&nmc->nmc_config);
|
||||
|
||||
/* The VPN connections don't have devices (yet?). */
|
||||
p = nm_client_get_active_connections (nmc->client);
|
||||
for (i = 0; i < p->len; i++) {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright 2010 - 2015 Red Hat, Inc.
|
||||
* Copyright 2010 - 2017 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include "nm-default.h"
|
||||
|
@ -93,7 +93,9 @@ complete_field (GHashTable *h, const NmcMetaGenericInfo *const*field)
|
|||
static void
|
||||
complete_one (gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
const char *prefix = user_data;
|
||||
const char **option_with_value = user_data;
|
||||
const char *option = option_with_value[0];
|
||||
const char *prefix = option_with_value[1];
|
||||
const char *name = key;
|
||||
const char *last;
|
||||
|
||||
|
@ -104,16 +106,23 @@ complete_one (gpointer key, gpointer value, gpointer user_data)
|
|||
last = prefix;
|
||||
|
||||
if ((!*last && !strchr (name, '.')) || matches (last, name)) {
|
||||
if (option != prefix) {
|
||||
/* value prefix was not a standalone argument,
|
||||
* it was part of --option=<value> argument.
|
||||
* Repeat the part leading to "=". */
|
||||
g_print ("%s=", option);
|
||||
}
|
||||
g_print ("%.*s%s%s\n", (int)(last-prefix), prefix, name,
|
||||
strcmp (last, name) == 0 ? "," : "");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
complete_fields (const char *prefix)
|
||||
complete_fields (const char *option, const char *prefix)
|
||||
{
|
||||
guint i;
|
||||
GHashTable *h;
|
||||
const char *option_with_value[2] = { option, prefix };
|
||||
|
||||
h = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
|
||||
|
@ -144,10 +153,30 @@ complete_fields (const char *prefix)
|
|||
for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++)
|
||||
complete_field_setting (h, i);
|
||||
|
||||
g_hash_table_foreach (h, complete_one, (gpointer) prefix);
|
||||
g_hash_table_foreach (h, complete_one, (gpointer) &option_with_value[0]);
|
||||
g_hash_table_destroy (h);
|
||||
}
|
||||
|
||||
static void
|
||||
complete_option_with_value (const char *option, const char *prefix, ...)
|
||||
{
|
||||
va_list args;
|
||||
const char *candidate;
|
||||
|
||||
va_start (args, prefix);
|
||||
while ((candidate = va_arg (args, const char *))) {
|
||||
if (!*prefix || matches (prefix, candidate)) {
|
||||
if (option != prefix) {
|
||||
/* value prefix was not a standalone argument,
|
||||
* it was part of --option=<value> argument.
|
||||
* Repeat the part leading to "=". */
|
||||
g_print ("%s=", option);
|
||||
}
|
||||
g_print ("%s\n", candidate);
|
||||
}
|
||||
}
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
static void
|
||||
usage (void)
|
||||
|
@ -190,6 +219,57 @@ static const NMCCommand nmcli_cmds[] = {
|
|||
{ NULL, do_overview, usage, TRUE, TRUE },
|
||||
};
|
||||
|
||||
static gboolean
|
||||
matches_arg (NmCli *nmc, int *argc, char ***argv, const char *pattern, char **arg)
|
||||
{
|
||||
char *opt = *argv[0];
|
||||
|
||||
if (nmc->return_value != NMC_RESULT_SUCCESS) {
|
||||
/* Don't process further matches if there has been an error. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (opt[1] == '-') {
|
||||
/* We know one '-' was already seen by the caller.
|
||||
* Skip it if there's a second one*/
|
||||
opt++;
|
||||
}
|
||||
|
||||
if (arg) {
|
||||
/* If there's a "=" separator, replace it with NUL so that matches()
|
||||
* works and consider the part after it to be the arguemnt's value. */
|
||||
*arg = strchr (opt, '=');
|
||||
if (*arg) {
|
||||
**arg = '\0';
|
||||
(*arg)++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!matches (opt, pattern)) {
|
||||
if (arg && *arg) {
|
||||
/* Back off the replacement of "=". */
|
||||
(*arg)--;
|
||||
**arg = '=';
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (arg && !*arg) {
|
||||
/* We need a value, but the option didn't contain a "=<value>" part.
|
||||
* Proceed to the next argument. */
|
||||
(*argc)--;
|
||||
(*argv)++;
|
||||
if (!*argc) {
|
||||
g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return FALSE;
|
||||
}
|
||||
*arg = *argv[0];
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
process_command_line (NmCli *nmc, int argc, char **argv)
|
||||
{
|
||||
|
@ -209,26 +289,24 @@ process_command_line (NmCli *nmc, int argc, char **argv)
|
|||
|
||||
/* parse options */
|
||||
while (argc) {
|
||||
char *opt = argv[0];
|
||||
if (opt[0] != '-')
|
||||
char *value;
|
||||
|
||||
if (argv[0][0] != '-')
|
||||
break;
|
||||
|
||||
if (argc == 1 && nmc->complete) {
|
||||
nmc_complete_strings (opt, "--terse", "--pretty", "--mode", "--colors", "--escape",
|
||||
nmc_complete_strings (argv[0], "--terse", "--pretty", "--mode", "--colors", "--escape",
|
||||
"--fields", "--nocheck", "--get-values",
|
||||
"--wait", "--version", "--help", NULL);
|
||||
}
|
||||
|
||||
if (opt[1] == '-') {
|
||||
opt++;
|
||||
if (argv[0][1] == '-' && argv[0][2] == '\0') {
|
||||
/* '--' ends options */
|
||||
if (opt[1] == '\0') {
|
||||
next_arg (nmc, &argc, &argv, NULL);
|
||||
break;
|
||||
}
|
||||
next_arg (nmc, &argc, &argv, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (matches (opt, "-terse")) {
|
||||
if (matches_arg (nmc, &argc, &argv, "-terse", NULL)) {
|
||||
if (nmc->nmc_config.print_output == NMC_PRINT_TERSE) {
|
||||
g_string_printf (nmc->return_text, _("Error: Option '--terse' is specified the second time."));
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
|
@ -241,7 +319,7 @@ process_command_line (NmCli *nmc, int argc, char **argv)
|
|||
}
|
||||
else
|
||||
nmc->nmc_config_mutable.print_output = NMC_PRINT_TERSE;
|
||||
} else if (matches (opt, "-pretty")) {
|
||||
} else if (matches_arg (nmc, &argc, &argv, "-pretty", NULL)) {
|
||||
if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) {
|
||||
g_string_printf (nmc->return_text, _("Error: Option '--pretty' is specified the second time."));
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
|
@ -254,126 +332,86 @@ process_command_line (NmCli *nmc, int argc, char **argv)
|
|||
}
|
||||
else
|
||||
nmc->nmc_config_mutable.print_output = NMC_PRINT_PRETTY;
|
||||
} else if (matches (opt, "-mode")) {
|
||||
} else if (matches_arg (nmc, &argc, &argv, "-mode", &value)) {
|
||||
nmc->mode_specified = TRUE;
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return FALSE;
|
||||
}
|
||||
if (argc == 1 && nmc->complete)
|
||||
nmc_complete_strings (argv[0], "tabular", "multiline", NULL);
|
||||
if (matches (argv[0], "tabular"))
|
||||
complete_option_with_value (argv[0], value, "tabular", "multiline", NULL);
|
||||
if (matches (value, "tabular"))
|
||||
nmc->nmc_config_mutable.multiline_output = FALSE;
|
||||
else if (matches (argv[0], "multiline"))
|
||||
else if (matches (value, "multiline"))
|
||||
nmc->nmc_config_mutable.multiline_output = TRUE;
|
||||
else {
|
||||
g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[0], opt);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return FALSE;
|
||||
}
|
||||
} else if (matches (opt, "-colors")) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
|
||||
g_string_printf (nmc->return_text, _("Error: '%s' is not a valid argument for '%s' option."), value, argv[0]);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return FALSE;
|
||||
}
|
||||
} else if (matches_arg (nmc, &argc, &argv, "-colors", &value)) {
|
||||
if (argc == 1 && nmc->complete)
|
||||
nmc_complete_strings (argv[0], "yes", "no", "auto", NULL);
|
||||
if (matches (argv[0], "auto"))
|
||||
complete_option_with_value (argv[0], value, "yes", "no", "auto", NULL);
|
||||
if (matches (value, "auto"))
|
||||
nmc->nmc_config_mutable.use_colors = NMC_USE_COLOR_AUTO;
|
||||
else if (matches (argv[0], "yes"))
|
||||
else if (matches (value, "yes"))
|
||||
nmc->nmc_config_mutable.use_colors = NMC_USE_COLOR_YES;
|
||||
else if (matches (argv[0], "no"))
|
||||
else if (matches (value, "no"))
|
||||
nmc->nmc_config_mutable.use_colors = NMC_USE_COLOR_NO;
|
||||
else {
|
||||
g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[0], opt);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return FALSE;
|
||||
}
|
||||
} else if (matches (opt, "-escape")) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
|
||||
g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), value, argv[0]);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return FALSE;
|
||||
}
|
||||
} else if (matches_arg (nmc, &argc, &argv, "-escape", &value)) {
|
||||
if (argc == 1 && nmc->complete)
|
||||
nmc_complete_strings (argv[0], "yes", "no", NULL);
|
||||
if (matches (argv[0], "yes"))
|
||||
complete_option_with_value (argv[0], value, "yes", "no", NULL);
|
||||
if (matches (value, "yes"))
|
||||
nmc->nmc_config_mutable.escape_values = TRUE;
|
||||
else if (matches (argv[0], "no"))
|
||||
else if (matches (value, "no"))
|
||||
nmc->nmc_config_mutable.escape_values = FALSE;
|
||||
else {
|
||||
g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[0], opt);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return FALSE;
|
||||
}
|
||||
} else if (matches (opt, "-fields")) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
g_string_printf (nmc->return_text, _("Error: fields for '%s' options are missing."), opt);
|
||||
g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), value, argv[0]);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return FALSE;
|
||||
}
|
||||
} else if (matches_arg (nmc, &argc, &argv, "-fields", &value)) {
|
||||
if (argc == 1 && nmc->complete)
|
||||
complete_fields (argv[0]);
|
||||
nmc->required_fields = g_strdup (argv[0]);
|
||||
} else if (matches (opt, "-get-values")) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
g_string_printf (nmc->return_text, _("Error: fields for '%s' options are missing."), opt);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return FALSE;
|
||||
}
|
||||
complete_fields (argv[0], value);
|
||||
nmc->required_fields = g_strdup (value);
|
||||
} else if (matches_arg (nmc, &argc, &argv, "-get-values", &value)) {
|
||||
if (argc == 1 && nmc->complete)
|
||||
complete_fields (argv[0]);
|
||||
nmc->required_fields = g_strdup (argv[0]);
|
||||
complete_fields (argv[0], value);
|
||||
nmc->required_fields = g_strdup (value);
|
||||
nmc->nmc_config_mutable.print_output = NMC_PRINT_TERSE;
|
||||
/* We want fixed tabular mode here, but just set the mode specified and rely on the initialization
|
||||
* in nmc_init: in this way we allow use of "-m multiline" to swap the output mode also if placed
|
||||
* before the "-g <field>" option (-g may be still more practical and easy to remember than -t -f).
|
||||
*/
|
||||
nmc->mode_specified = TRUE;
|
||||
} else if (matches (opt, "-nocheck")) {
|
||||
} else if (matches_arg (nmc, &argc, &argv, "-nocheck", NULL)) {
|
||||
/* ignore for backward compatibility */
|
||||
} else if (matches (opt, "-wait")) {
|
||||
} else if (matches_arg (nmc, &argc, &argv, "-wait", &value)) {
|
||||
unsigned long timeout;
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return FALSE;
|
||||
}
|
||||
if (!nmc_string_to_uint (argv[0], TRUE, 0, G_MAXINT, &timeout)) {
|
||||
g_string_printf (nmc->return_text, _("Error: '%s' is not a valid timeout for '%s' option."),
|
||||
argv[0], opt);
|
||||
if (!nmc_string_to_uint (value, TRUE, 0, G_MAXINT, &timeout)) {
|
||||
g_string_printf (nmc->return_text, _("Error: '%s' is not a valid timeout."), value);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return FALSE;
|
||||
}
|
||||
nmc->timeout = (int) timeout;
|
||||
} else if (matches (opt, "-version")) {
|
||||
} else if (matches_arg (nmc, &argc, &argv, "-version", NULL)) {
|
||||
if (!nmc->complete)
|
||||
g_print (_("nmcli tool, version %s\n"), NMCLI_VERSION);
|
||||
return NMC_RESULT_SUCCESS;
|
||||
} else if (matches (opt, "-help")) {
|
||||
} else if (matches_arg (nmc, &argc, &argv, "-help", NULL)) {
|
||||
if (!nmc->complete)
|
||||
usage ();
|
||||
return NMC_RESULT_SUCCESS;
|
||||
} else {
|
||||
g_string_printf (nmc->return_text, _("Error: Option '%s' is unknown, try 'nmcli -help'."), opt);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
if (nmc->return_value == NMC_RESULT_SUCCESS) {
|
||||
g_string_printf (nmc->return_text, _("Error: Option '%s' is unknown, try 'nmcli -help'."), argv[0]);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
next_arg (nmc, &argc, &argv, NULL);
|
||||
}
|
||||
|
||||
|
@ -547,7 +585,9 @@ nmc_init (NmCli *nmc)
|
|||
static void
|
||||
nmc_cleanup (NmCli *nmc)
|
||||
{
|
||||
if (nmc->client) g_object_unref (nmc->client);
|
||||
pid_t ret;
|
||||
|
||||
g_clear_object (&nmc->client);
|
||||
|
||||
g_string_free (nmc->return_text, TRUE);
|
||||
|
||||
|
@ -561,6 +601,15 @@ nmc_cleanup (NmCli *nmc)
|
|||
|
||||
g_free (nmc->required_fields);
|
||||
|
||||
if (nmc->pager_pid > 0) {
|
||||
fclose (stdout);
|
||||
fclose (stderr);
|
||||
do {
|
||||
ret = waitpid (nmc->pager_pid, NULL, 0);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
nmc->pager_pid = 0;
|
||||
}
|
||||
|
||||
nmc_polkit_agent_fini (nmc);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright 2010 - 2015 Red Hat, Inc.
|
||||
* Copyright 2010 - 2017 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef NMC_NMCLI_H
|
||||
|
@ -129,6 +129,7 @@ typedef struct _NmCli {
|
|||
|
||||
NMCResultCode return_value; /* Return code of nmcli */
|
||||
GString *return_text; /* Reason text */
|
||||
pid_t pager_pid; /* PID of a pager, if one was spawned */
|
||||
|
||||
int timeout; /* Operation timeout */
|
||||
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright 2010 - 2015 Red Hat, Inc.
|
||||
* Copyright 2010 Lennart Poettering
|
||||
* Copyright 2010 - 2017 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include "nm-default.h"
|
||||
|
@ -28,6 +29,7 @@
|
|||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#include "nm-client-utils.h"
|
||||
#include "nm-meta-setting-access.h"
|
||||
|
@ -122,7 +124,7 @@ use_colors (NmcColorOption color_option)
|
|||
|
||||
if (G_UNLIKELY (cached == NMC_USE_COLOR_AUTO)) {
|
||||
if ( g_strcmp0 (g_getenv ("TERM"), "dumb") == 0
|
||||
|| !isatty (fileno (stdout)))
|
||||
|| !isatty (STDOUT_FILENO))
|
||||
cached = NMC_USE_COLOR_NO;
|
||||
else
|
||||
cached = NMC_USE_COLOR_YES;
|
||||
|
@ -1450,6 +1452,109 @@ nmc_print (const NmcConfig *nmc_config,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
pager_fallback (void)
|
||||
{
|
||||
char buf[64];
|
||||
int rb;
|
||||
|
||||
do {
|
||||
rb = read (STDIN_FILENO, buf, sizeof (buf));
|
||||
if (rb == -1) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
} else {
|
||||
g_printerr (_("Error reading nmcli output: %s\n"), strerror (errno));
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (write (STDOUT_FILENO, buf, rb) == -1) {
|
||||
g_printerr (_("Error writing nmcli output: %s\n"), strerror (errno));
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
} while (rb > 0);
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
nmc_terminal_spawn_pager (const NmcConfig *nmc_config)
|
||||
{
|
||||
const char *pager = getenv ("PAGER");
|
||||
pid_t parent_pid;
|
||||
int fd[2];
|
||||
|
||||
if ( nm_cli.pager_pid > 0
|
||||
|| nmc_config->print_output == NMC_PRINT_TERSE
|
||||
|| !use_colors (nmc_config->use_colors)
|
||||
|| g_strcmp0 (pager, "") == 0)
|
||||
return;
|
||||
|
||||
if (pipe (fd) == -1) {
|
||||
g_printerr (_("Failed to create pager pipe: %s\n"), strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
parent_pid = getpid ();
|
||||
|
||||
nm_cli.pager_pid = fork ();
|
||||
if (nm_cli.pager_pid == -1) {
|
||||
g_printerr (_("Failed to fork pager: %s\n"), strerror (errno));
|
||||
close (fd[0]);
|
||||
close (fd[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* In the child start the pager */
|
||||
if (nm_cli.pager_pid == 0) {
|
||||
dup2 (fd[0], STDIN_FILENO);
|
||||
close (fd[0]);
|
||||
close (fd[1]);
|
||||
|
||||
setenv ("LESS", "FRSXMK", 1);
|
||||
setenv ("LESSCHARSET", "utf-8", 1);
|
||||
|
||||
/* Make sure the pager goes away when the parent dies */
|
||||
if (prctl (PR_SET_PDEATHSIG, SIGTERM) < 0)
|
||||
_exit (EXIT_FAILURE);
|
||||
|
||||
/* Check whether our parent died before we were able
|
||||
* to set the death signal */
|
||||
if (getppid () != parent_pid)
|
||||
_exit (EXIT_SUCCESS);
|
||||
|
||||
if (pager) {
|
||||
execlp (pager, pager, NULL);
|
||||
execl ("/bin/sh", "sh", "-c", pager, NULL);
|
||||
}
|
||||
|
||||
/* Debian's alternatives command for pagers is
|
||||
* called 'pager'. Note that we do not call
|
||||
* sensible-pagers here, since that is just a
|
||||
* shell script that implements a logic that
|
||||
* is similar to this one anyway, but is
|
||||
* Debian-specific. */
|
||||
execlp ("pager", "pager", NULL);
|
||||
|
||||
execlp ("less", "less", NULL);
|
||||
execlp ("more", "more", NULL);
|
||||
|
||||
pager_fallback ();
|
||||
/* not reached */
|
||||
}
|
||||
|
||||
/* Return in the parent */
|
||||
if (dup2 (fd[1], STDOUT_FILENO) < 0)
|
||||
g_printerr (_("Failed to duplicate pager pipe: %s\n"), strerror (errno));
|
||||
if (dup2 (fd[1], STDERR_FILENO) < 0)
|
||||
g_printerr (_("Failed to duplicate pager pipe: %s\n"), strerror (errno));
|
||||
|
||||
close (fd[0]);
|
||||
close (fd[1]);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static const char *
|
||||
get_value_to_print (NmcColorOption color_option,
|
||||
const NmcOutputField *field,
|
||||
|
@ -1514,6 +1619,9 @@ print_required_fields (const NmcConfig *nmc_config,
|
|||
gboolean field_names = of_flags & NMC_OF_FLAG_FIELD_NAMES;
|
||||
gboolean section_prefix = of_flags & NMC_OF_FLAG_SECTION_PREFIX;
|
||||
|
||||
/* Optionally start paging the output. */
|
||||
nmc_terminal_spawn_pager (nmc_config);
|
||||
|
||||
/* --- Main header --- */
|
||||
if ((main_header_add || main_header_only) && pretty) {
|
||||
gs_free char *line = NULL;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright 2010 - 2015 Red Hat, Inc.
|
||||
* Copyright 2010 - 2017 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef NMC_UTILS_H
|
||||
|
@ -40,6 +40,8 @@ gboolean nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, char ***a
|
|||
char *ssid_to_hex (const char *str, gsize len);
|
||||
void nmc_terminal_erase_line (void);
|
||||
void nmc_terminal_show_progress (const char *str);
|
||||
void nmc_terminal_spawn_pager (const NmcConfig *nmc_config);
|
||||
gboolean nmc_term_use_colors (NmcColorOption color_option);
|
||||
const char *nmc_term_color_sequence (NMMetaTermColor color);
|
||||
const char *nmc_term_format_sequence (NMMetaTermFormat format);
|
||||
NMMetaTermColor nmc_term_color_parse_string (const char *str, GError **error);
|
||||
|
|
Loading…
Reference in a new issue