mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-01 23:30:13 +01:00
cli: spawn a pager when running on a terminal
This makes it a lot more convenient to deal with long outputs (such as "nmcli c show id ..."). The implementation is essentially jacked from systemd. The bugs are mine.
This commit is contained in:
parent
6fde475b27
commit
24c079e4b2
5 changed files with 132 additions and 8 deletions
|
|
@ -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"
|
||||
|
|
@ -148,7 +148,6 @@ complete_fields (const char *prefix)
|
|||
g_hash_table_destroy (h);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usage (void)
|
||||
{
|
||||
|
|
@ -547,7 +546,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 +562,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…
Add table
Reference in a new issue