MINOR: cli: add an option to display the uptime in the CLI's prompt

Entering "prompt timed" toggles reporting of the process' uptime in
the prompt, which will report days, hours, minutes and seconds since
it was started. As discussed with Tim in issue #2145, this can be
convenient to roughly estimate the time between two outputs, as well
as detecting that a process failed to be reloaded for example.
diff --git a/doc/management.txt b/doc/management.txt
index 4a5e033..f226d99 100644
--- a/doc/management.txt
+++ b/doc/management.txt
@@ -1497,6 +1497,20 @@
    ...
    >
 
+Optionally the process' uptime may be displayed in the prompt. In order to
+enable this, the "prompt timed" command will enable the prompt and toggle the
+displaying of the time. The uptime is displayed in format "d:hh:mm:ss" where
+"d" is the number of days, and "hh", "mm", "ss" are respectively the number
+of hours, minutes and seconds on two digits each:
+
+   # socat /var/run/haproxy readline
+   prompt timed
+
+   [23:03:34:39]> show version
+   2.8-dev9-e5e622-18
+
+   [23:03:34:41]> quit
+
 Since multiple commands may be issued at once, haproxy uses the empty line as a
 delimiter to mark an end of output for each command, and takes care of ensuring
 that no command can emit an empty line on output. A script can thus easily
diff --git a/include/haproxy/cli-t.h b/include/haproxy/cli-t.h
index 104b0b1..0570b69 100644
--- a/include/haproxy/cli-t.h
+++ b/include/haproxy/cli-t.h
@@ -42,6 +42,7 @@
 #define APPCTX_CLI_ST1_PROMPT  (1 << 0)
 #define APPCTX_CLI_ST1_PAYLOAD (1 << 1)
 #define APPCTX_CLI_ST1_NOLF    (1 << 2)
+#define APPCTX_CLI_ST1_TIMED   (1 << 3)
 
 #define CLI_PREFIX_KW_NB 5
 #define CLI_MAX_MATCHES 5
diff --git a/src/cli.c b/src/cli.c
index d66e483..f81cfa6 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -319,7 +319,7 @@
 	/* always show the prompt/help/quit commands */
 	chunk_strcat(tmp,
 	             "  help [<command>]                        : list matching or all commands\n"
-	             "  prompt                                  : toggle interactive mode with prompt\n"
+	             "  prompt [timed]                          : toggle interactive mode with prompt\n"
 	             "  quit                                    : disconnect\n");
 
 	chunk_init(&out, NULL, 0);
@@ -1115,6 +1115,7 @@
 
 			/* The post-command prompt is either LF alone or LF + '> ' in interactive mode */
 			if (appctx->st0 == CLI_ST_PROMPT) {
+				char prompt_buf[20];
 				const char *prompt = "";
 
 				if (appctx->st1 & APPCTX_CLI_ST1_PROMPT) {
@@ -1124,6 +1125,13 @@
 					 */
 					if (appctx->chunk->data && appctx->st1 & APPCTX_CLI_ST1_PAYLOAD)
 						prompt = "+ ";
+					else if (appctx->st1 & APPCTX_CLI_ST1_TIMED) {
+						uint up = ns_to_sec(now_ns - start_time_ns);
+						snprintf(prompt_buf, sizeof(prompt_buf),
+							 "\n[%u:%02u:%02u:%02u]> ",
+							 (up / 86400), (up / 3600) % 24, (up / 60) % 60, up % 60);
+						prompt = prompt_buf;
+					}
 					else
 						prompt = "\n> ";
 				}
@@ -2187,7 +2195,12 @@
 		cli_gen_usage_msg(appctx, args);
 	else if (*args[0] == 'p')
 		/* prompt */
-		appctx->st1 ^= APPCTX_CLI_ST1_PROMPT;
+		if (strcmp(args[1], "timed") == 0) {
+			appctx->st1 |= APPCTX_CLI_ST1_PROMPT;
+			appctx->st1 ^= APPCTX_CLI_ST1_TIMED;
+		}
+		else
+			appctx->st1 ^= APPCTX_CLI_ST1_PROMPT;
 	else if (*args[0] == 'q') {
 		/* quit */
 		se_fl_set(appctx->sedesc, SE_FL_EOI);