MINOR: master/cli: also implement the timed prompt on the master CLI

This provides more consistency between the master and the worker. When
"prompt timed" is passed on the master, the timed mode is toggled. When
enabled, for a master it will show the master process' uptime, and for
a worker it will show this worker's uptime. Example:

  master> prompt timed
  [0:00:00:50] master> show proc
  #<PID>          <type>          <reloads>       <uptime>        <version>
  11940           master          1 [failed: 0]   0d00h02m10s     2.8-dev11-474c14-21
  # workers
  11955           worker          0               0d00h00m59s     2.8-dev11-474c14-21
  # old workers
  11942           worker          1               0d00h02m10s     2.8-dev11-474c14-21
  # programs

  [0:00:00:58] master> @!11955
  [0:00:01:03] 11955> @!11942
  [0:00:02:17] 11942> @
  [0:00:01:10] master>
diff --git a/doc/management.txt b/doc/management.txt
index f226d99..2bac0e9 100644
--- a/doc/management.txt
+++ b/doc/management.txt
@@ -1511,6 +1511,18 @@
 
    [23:03:34:41]> quit
 
+When the timed prompt is set on the master CLI, the prompt will display the
+currently selected process' uptime, so this will work for the master, current
+worker or an older worker:
+
+  master> prompt timed
+  [0:00:00:50] master> show proc
+  (...)
+  [0:00:00:58] master> @!11955     <-- master, switch to current worker
+  [0:00:01:03] 11955> @!11942      <-- current worker, switch to older worker
+  [0:00:02:17] 11942> @            <-- older worker, switch back to master
+  [0:00:01:10] master>
+
 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/stream-t.h b/include/haproxy/stream-t.h
index 14293d5..aa84ebf 100644
--- a/include/haproxy/stream-t.h
+++ b/include/haproxy/stream-t.h
@@ -132,6 +132,7 @@
 #define PCLI_F_PROMPT   0x10000
 #define PCLI_F_PAYLOAD  0x20000
 #define PCLI_F_RELOAD   0x40000 /* this is the "reload" stream, quits after displaying reload status */
+#define PCLI_F_TIMED    0x80000 /* the prompt shows the process' uptime */
 
 
 /* error types reported on the streams for more accurate reporting.
diff --git a/src/cli.c b/src/cli.c
index f81cfa6..d8675e1 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -2221,11 +2221,46 @@
 	if (s->pcli_flags & PCLI_F_PAYLOAD) {
 		chunk_appendf(msg, "+ ");
 	} else {
-		if (s->pcli_next_pid == 0)
+		if (s->pcli_next_pid == 0) {
+			/* master's prompt */
+			if (s->pcli_flags & PCLI_F_TIMED) {
+				uint up = ns_to_sec(now_ns - start_time_ns);
+				chunk_appendf(msg, "[%u:%02u:%02u:%02u] ",
+				         (up / 86400), (up / 3600) % 24, (up / 60) % 60, up % 60);
+			}
+
 			chunk_appendf(msg, "master%s",
 			              (proc_self->failedreloads > 0) ? "[ReloadFailed]" : "");
-		else
+		}
+		else {
+			/* worker's prompt */
+			if (s->pcli_flags & PCLI_F_TIMED) {
+				const struct mworker_proc *tmp, *proc;
+				uint up;
+
+				/* set proc to the worker corresponding to pcli_next_pid or NULL */
+				proc = NULL;
+				list_for_each_entry(tmp, &proc_list, list) {
+					if (!(tmp->options & PROC_O_TYPE_WORKER))
+						continue;
+					if (tmp->pid == s->pcli_next_pid) {
+						proc = tmp;
+						break;
+					}
+				}
+
+				if (!proc)
+					chunk_appendf(msg, "[gone] ");
+				else {
+					up = date.tv_sec - proc->timestamp;
+					if ((int)up < 0) /* must never be negative because of clock drift */
+						up = 0;
+					chunk_appendf(msg, "[%u:%02u:%02u:%02u] ",
+						      (up / 86400), (up / 3600) % 24, (up / 60) % 60, up % 60);
+				}
+			}
 			chunk_appendf(msg, "%d", s->pcli_next_pid);
+		}
 
 		if (s->pcli_flags & (ACCESS_EXPERIMENTAL|ACCESS_EXPERT|ACCESS_MCLI_DEBUG)) {
 			chunk_appendf(msg, "(");
@@ -2368,9 +2403,13 @@
 			*next_pid = target_pid;
 		return 1;
 	} else if (strcmp("prompt", args[0]) == 0) {
-		s->pcli_flags ^= PCLI_F_PROMPT;
+		if (argl >= 2 && strcmp(args[1], "timed") == 0) {
+			s->pcli_flags |= PCLI_F_PROMPT;
+			s->pcli_flags ^= PCLI_F_TIMED;
+		}
+		else
+			s->pcli_flags ^= PCLI_F_PROMPT;
 		return argl; /* return the number of elements in the array */
-
 	} else if (strcmp("quit", args[0]) == 0) {
 		sc_schedule_abort(s->scf);
 		sc_schedule_shutdown(s->scf);