Browse Source

pager: Working pager on client side

Serj Kalichev 1 year ago
parent
commit
6c79c93c2a
4 changed files with 50 additions and 10 deletions
  1. 45 6
      bin/klish/interactive.c
  2. 1 1
      bin/klish/private.h
  3. 3 3
      klish.conf
  4. 1 0
      klish/ktp_session.h

+ 45 - 6
bin/klish/interactive.c

@@ -1,9 +1,11 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <assert.h>
+#include <sys/types.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <string.h>
+#include <sys/wait.h>
 
 #include <faux/faux.h>
 #include <faux/str.h>
@@ -21,6 +23,8 @@ typedef struct ctx_s {
 	tinyrl_t *tinyrl;
 	struct options *opts;
 	char *hotkeys[VT100_HOTKEY_MAP_LEN];
+	tri_t pager_working;
+	FILE *pager_pipe;
 } ctx_t;
 
 
@@ -75,9 +79,8 @@ int klish_interactive_shell(ktp_session_t *ktp, struct options *opts)
 	ctx.tinyrl = tinyrl;
 	ctx.opts = opts;
 	faux_bzero(ctx.hotkeys, sizeof(ctx.hotkeys));
-
-	// Replace common stdout callback by interactive-specific one.
-	ktp_session_set_cb(ktp, KTP_SESSION_CB_STDOUT, interactive_stdout_cb, &ctx);
+	ctx.pager_working = TRI_UNDEFINED;
+	ctx.pager_pipe = NULL;
 
 	// Now AUTH command is used only for starting hand-shake and getting
 	// prompt from the server. Generally it must be necessary for
@@ -88,6 +91,10 @@ int klish_interactive_shell(ktp_session_t *ktp, struct options *opts)
 	if (auth_rc < 0)
 		goto cleanup;
 
+	// Replace common stdout callback by interactive-specific one.
+	// Place it after auth to make auth use standard stdout callback.
+	ktp_session_set_cb(ktp, KTP_SESSION_CB_STDOUT, interactive_stdout_cb, &ctx);
+
 	// Don't stop interactive loop on each answer
 	ktp_session_set_stop_on_answer(ktp, BOOL_FALSE);
 
@@ -240,6 +247,13 @@ bool_t cmd_ack_cb(ktp_session_t *ktp, const faux_msg_t *msg, void *udata)
 	}
 	faux_error_free(error);
 
+	// Wait for pager
+	if (ctx->pager_working == TRI_TRUE) {
+		pclose(ctx->pager_pipe);
+		ctx->pager_working = TRI_UNDEFINED;
+		ctx->pager_pipe = NULL;
+	}
+
 	tinyrl_set_busy(ctx->tinyrl, BOOL_FALSE);
 	if (!ktp_session_done(ktp))
 		tinyrl_redisplay(ctx->tinyrl);
@@ -572,10 +586,35 @@ static bool_t interactive_stdout_cb(ktp_session_t *ktp, const char *line, size_t
 {
 	ctx_t *ctx = (ctx_t *)udata;
 
-	if (write(STDOUT_FILENO, line, len) < 0)
-		return BOOL_FALSE;
+	assert(ctx);
 
-	ktp = ktp; // Happy compiler
+	// Start pager if necessary
+	if (
+		ctx->opts->pager_enabled && // Pager enabled within config file
+		(ctx->pager_working == TRI_UNDEFINED) && // Pager is not working
+		!(ktp_session_cmd_features(ktp) & KTP_STATUS_INTERACTIVE) // Non interactive command
+		) {
+
+		ctx->pager_pipe = popen(ctx->opts->pager, "we");
+		if (!ctx->pager_pipe)
+			ctx->pager_working = BOOL_FALSE; // Indicates can't start
+		else
+			ctx->pager_working = BOOL_TRUE;
+	}
+
+	// Write to pager's pipe if pager is really working
+	if (ctx->pager_working == TRI_TRUE) {
+		if (fwrite(line, 1, len, ctx->pager_pipe) == 0) {
+			// If we can't write to pager pipe then try stdout.
+			if (write(STDOUT_FILENO, line, len) < 0)
+				return BOOL_FALSE;
+			return BOOL_TRUE; // Don't break the loop
+		}
+		fflush(ctx->pager_pipe);
+	} else {
+		if (write(STDOUT_FILENO, line, len) < 0)
+			return BOOL_FALSE;
+	}
 
 	return BOOL_TRUE;
 }

+ 1 - 1
bin/klish/private.h

@@ -7,7 +7,7 @@
 #endif
 
 #define DEFAULT_CFGFILE "/etc/klish/klish.conf"
-#define DEFAULT_PAGER "/usr/bin/less -I -F -e -X -K -d"
+#define DEFAULT_PAGER "/usr/bin/less -I -F -e -X -K -d -r"
 
 /** @brief Command line and config file options
  */

+ 3 - 3
klish.conf

@@ -6,9 +6,9 @@
 #UnixSocketPath=/tmp/klish-unix-socket
 
 # The klish can use external pager for non-interactive commands. By default it
-# will execute "/usr/bin/less -I -F -e -X -K -d" process as a pager.
-#Pager=/usr/bin/less -I -F -e -X -K -d
+# will execute "/usr/bin/less -I -F -e -X -K -d -r" process as a pager.
+Pager=/usr/bin/less -I -F -e -X -K -d -r
 
 # External pager is enabled by default. But user can explicitly enable or
 # disable it. Use "y" or "n" values.
-# UsePager=y
+#UsePager=y

+ 1 - 0
klish/ktp_session.h

@@ -94,6 +94,7 @@ bool_t ktp_session_completion(ktp_session_t *ktp, const char *line,
 	bool_t dry_run);
 bool_t ktp_session_help(ktp_session_t *ktp, const char *line);
 bool_t ktp_session_retcode(ktp_session_t *ktp, int *retcode);
+ktp_status_e ktp_session_cmd_features(const ktp_session_t *ktp);
 
 
 // Server KTP session