REORG: cli: move "show info" to stats.c

Move the "show info" command to stats.c using the CLI keyword API
to register it on the CLI. The stats_dump_info_to_buffer() function
is now static again. Note, we don't need proto_ssl anymore in cli.c.
diff --git a/include/types/cli.h b/include/types/cli.h
index 9c7bed5..883c72d 100644
--- a/include/types/cli.h
+++ b/include/types/cli.h
@@ -38,69 +38,6 @@
 	struct cli_kw kw[VAR_ARRAY];
 };
 
-/* Show Info fields for CLI output. For any field added here, please add the text
- * representation in the info_field_names array below. Please only append at the end,
- * before the INF_TOTAL_FIELDS entry, and never insert anything in the middle
- * nor at the beginning.
- */
-enum info_field {
-	INF_NAME,
-	INF_VERSION,
-	INF_RELEASE_DATE,
-	INF_NBPROC,
-	INF_PROCESS_NUM,
-	INF_PID,
-	INF_UPTIME,
-	INF_UPTIME_SEC,
-	INF_MEMMAX_MB,
-	INF_POOL_ALLOC_MB,
-	INF_POOL_USED_MB,
-	INF_POOL_FAILED,
-	INF_ULIMIT_N,
-	INF_MAXSOCK,
-	INF_MAXCONN,
-	INF_HARD_MAXCONN,
-	INF_CURR_CONN,
-	INF_CUM_CONN,
-	INF_CUM_REQ,
-	INF_MAX_SSL_CONNS,
-	INF_CURR_SSL_CONNS,
-	INF_CUM_SSL_CONNS,
-	INF_MAXPIPES,
-	INF_PIPES_USED,
-	INF_PIPES_FREE,
-	INF_CONN_RATE,
-	INF_CONN_RATE_LIMIT,
-	INF_MAX_CONN_RATE,
-	INF_SESS_RATE,
-	INF_SESS_RATE_LIMIT,
-	INF_MAX_SESS_RATE,
-	INF_SSL_RATE,
-	INF_SSL_RATE_LIMIT,
-	INF_MAX_SSL_RATE,
-	INF_SSL_FRONTEND_KEY_RATE,
-	INF_SSL_FRONTEND_MAX_KEY_RATE,
-	INF_SSL_FRONTEND_SESSION_REUSE_PCT,
-	INF_SSL_BACKEND_KEY_RATE,
-	INF_SSL_BACKEND_MAX_KEY_RATE,
-	INF_SSL_CACHE_LOOKUPS,
-	INF_SSL_CACHE_MISSES,
-	INF_COMPRESS_BPS_IN,
-	INF_COMPRESS_BPS_OUT,
-	INF_COMPRESS_BPS_RATE_LIM,
-	INF_ZLIB_MEM_USAGE,
-	INF_MAX_ZLIB_MEM_USAGE,
-	INF_TASKS,
-	INF_RUN_QUEUE,
-	INF_IDLE_PCT,
-	INF_NODE,
-	INF_DESCRIPTION,
-
-	/* must always be the last one */
-	INF_TOTAL_FIELDS
-};
-
-
 /* stats socket states */
 enum {
 	STAT_CLI_INIT = 0,   /* initial state, must leave to zero ! */
@@ -110,7 +47,6 @@
 	STAT_CLI_PROMPT,     /* display the prompt (first output, same code) */
 	STAT_CLI_PRINT,      /* display message in cli->msg */
 	STAT_CLI_PRINT_FREE, /* display message in cli->msg. After the display, free the pointer */
-	STAT_CLI_O_INFO,     /* dump info */
 	STAT_CLI_O_ERR,      /* dump errors */
 	STAT_CLI_O_TAB,      /* dump tables */
 	STAT_CLI_O_CLR,      /* clear tables */
diff --git a/include/types/stats.h b/include/types/stats.h
index dd52bba..48cf645 100644
--- a/include/types/stats.h
+++ b/include/types/stats.h
@@ -224,6 +224,69 @@
 	} u;
 };
 
+/* Show Info fields for CLI output. For any field added here, please add the text
+ * representation in the info_field_names array below. Please only append at the end,
+ * before the INF_TOTAL_FIELDS entry, and never insert anything in the middle
+ * nor at the beginning.
+ */
+enum info_field {
+	INF_NAME,
+	INF_VERSION,
+	INF_RELEASE_DATE,
+	INF_NBPROC,
+	INF_PROCESS_NUM,
+	INF_PID,
+	INF_UPTIME,
+	INF_UPTIME_SEC,
+	INF_MEMMAX_MB,
+	INF_POOL_ALLOC_MB,
+	INF_POOL_USED_MB,
+	INF_POOL_FAILED,
+	INF_ULIMIT_N,
+	INF_MAXSOCK,
+	INF_MAXCONN,
+	INF_HARD_MAXCONN,
+	INF_CURR_CONN,
+	INF_CUM_CONN,
+	INF_CUM_REQ,
+	INF_MAX_SSL_CONNS,
+	INF_CURR_SSL_CONNS,
+	INF_CUM_SSL_CONNS,
+	INF_MAXPIPES,
+	INF_PIPES_USED,
+	INF_PIPES_FREE,
+	INF_CONN_RATE,
+	INF_CONN_RATE_LIMIT,
+	INF_MAX_CONN_RATE,
+	INF_SESS_RATE,
+	INF_SESS_RATE_LIMIT,
+	INF_MAX_SESS_RATE,
+	INF_SSL_RATE,
+	INF_SSL_RATE_LIMIT,
+	INF_MAX_SSL_RATE,
+	INF_SSL_FRONTEND_KEY_RATE,
+	INF_SSL_FRONTEND_MAX_KEY_RATE,
+	INF_SSL_FRONTEND_SESSION_REUSE_PCT,
+	INF_SSL_BACKEND_KEY_RATE,
+	INF_SSL_BACKEND_MAX_KEY_RATE,
+	INF_SSL_CACHE_LOOKUPS,
+	INF_SSL_CACHE_MISSES,
+	INF_COMPRESS_BPS_IN,
+	INF_COMPRESS_BPS_OUT,
+	INF_COMPRESS_BPS_RATE_LIM,
+	INF_ZLIB_MEM_USAGE,
+	INF_MAX_ZLIB_MEM_USAGE,
+	INF_TASKS,
+	INF_RUN_QUEUE,
+	INF_IDLE_PCT,
+	INF_NODE,
+	INF_DESCRIPTION,
+
+	/* must always be the last one */
+	INF_TOTAL_FIELDS
+};
+
+
 /* Stats fields for CSV output. For any field added here, please add the text
  * representation in the stat_field_names array below. Please only append at the end,
  * before the ST_F_TOTAL_FIELDS entry, and never insert anything in the middle
diff --git a/src/cli.c b/src/cli.c
index cdfbebf..a395e23 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -67,74 +67,7 @@
 #include <proto/stream_interface.h>
 #include <proto/task.h>
 
-#ifdef USE_OPENSSL
-#include <proto/ssl_sock.h>
-#include <types/ssl_sock.h>
-#endif
-
-/* These are the field names for each INF_* field position. Please pay attention
- * to always use the exact same name except that the strings for new names must
- * be lower case or CamelCase while the enum entries must be upper case.
- */
-const char *info_field_names[INF_TOTAL_FIELDS] = {
-	[INF_NAME]                           = "Name",
-	[INF_VERSION]                        = "Version",
-	[INF_RELEASE_DATE]                   = "Release_date",
-	[INF_NBPROC]                         = "Nbproc",
-	[INF_PROCESS_NUM]                    = "Process_num",
-	[INF_PID]                            = "Pid",
-	[INF_UPTIME]                         = "Uptime",
-	[INF_UPTIME_SEC]                     = "Uptime_sec",
-	[INF_MEMMAX_MB]                      = "Memmax_MB",
-	[INF_POOL_ALLOC_MB]                  = "PoolAlloc_MB",
-	[INF_POOL_USED_MB]                   = "PoolUsed_MB",
-	[INF_POOL_FAILED]                    = "PoolFailed",
-	[INF_ULIMIT_N]                       = "Ulimit-n",
-	[INF_MAXSOCK]                        = "Maxsock",
-	[INF_MAXCONN]                        = "Maxconn",
-	[INF_HARD_MAXCONN]                   = "Hard_maxconn",
-	[INF_CURR_CONN]                      = "CurrConns",
-	[INF_CUM_CONN]                       = "CumConns",
-	[INF_CUM_REQ]                        = "CumReq",
-	[INF_MAX_SSL_CONNS]                  = "MaxSslConns",
-	[INF_CURR_SSL_CONNS]                 = "CurrSslConns",
-	[INF_CUM_SSL_CONNS]                  = "CumSslConns",
-	[INF_MAXPIPES]                       = "Maxpipes",
-	[INF_PIPES_USED]                     = "PipesUsed",
-	[INF_PIPES_FREE]                     = "PipesFree",
-	[INF_CONN_RATE]                      = "ConnRate",
-	[INF_CONN_RATE_LIMIT]                = "ConnRateLimit",
-	[INF_MAX_CONN_RATE]                  = "MaxConnRate",
-	[INF_SESS_RATE]                      = "SessRate",
-	[INF_SESS_RATE_LIMIT]                = "SessRateLimit",
-	[INF_MAX_SESS_RATE]                  = "MaxSessRate",
-	[INF_SSL_RATE]                       = "SslRate",
-	[INF_SSL_RATE_LIMIT]                 = "SslRateLimit",
-	[INF_MAX_SSL_RATE]                   = "MaxSslRate",
-	[INF_SSL_FRONTEND_KEY_RATE]          = "SslFrontendKeyRate",
-	[INF_SSL_FRONTEND_MAX_KEY_RATE]      = "SslFrontendMaxKeyRate",
-	[INF_SSL_FRONTEND_SESSION_REUSE_PCT] = "SslFrontendSessionReuse_pct",
-	[INF_SSL_BACKEND_KEY_RATE]           = "SslBackendKeyRate",
-	[INF_SSL_BACKEND_MAX_KEY_RATE]       = "SslBackendMaxKeyRate",
-	[INF_SSL_CACHE_LOOKUPS]              = "SslCacheLookups",
-	[INF_SSL_CACHE_MISSES]               = "SslCacheMisses",
-	[INF_COMPRESS_BPS_IN]                = "CompressBpsIn",
-	[INF_COMPRESS_BPS_OUT]               = "CompressBpsOut",
-	[INF_COMPRESS_BPS_RATE_LIM]          = "CompressBpsRateLim",
-	[INF_ZLIB_MEM_USAGE]                 = "ZlibMemUsage",
-	[INF_MAX_ZLIB_MEM_USAGE]             = "MaxZlibMemUsage",
-	[INF_TASKS]                          = "Tasks",
-	[INF_RUN_QUEUE]                      = "Run_queue",
-	[INF_IDLE_PCT]                       = "Idle_pct",
-	[INF_NODE]                           = "node",
-	[INF_DESCRIPTION]                    = "description",
-};
-
-/* one line of stats */
-static struct field info[INF_TOTAL_FIELDS];
-
 static int stats_dump_env_to_buffer(struct stream_interface *si);
-static int stats_dump_info_to_buffer(struct stream_interface *si);
 static int stats_dump_errors_to_buffer(struct stream_interface *si);
 static int stats_table_request(struct stream_interface *si, int show);
 
@@ -149,7 +82,6 @@
 	"  prompt         : toggle interactive mode with prompt\n"
 	"  quit           : disconnect\n"
 	"  show env [var] : dump environment variables known to the process\n"
-	"  show info      : report information about the running process\n"
 	"  show errors    : report last request and response errors for each proxy\n"
 	"  show table [id]: report table usage stats or dump this table's contents\n"
 	"  set table [id] : update or create a table entry's data\n"
@@ -1076,12 +1008,6 @@
 				appctx->st2 = STAT_ST_END;
 			}
 		}
-		else if (strcmp(args[1], "info") == 0) {
-			if (strcmp(args[2], "typed") == 0)
-				appctx->ctx.stats.flags |= STAT_FMT_TYPED;
-			appctx->st2 = STAT_ST_INIT;
-			appctx->st0 = STAT_CLI_O_INFO; // stats_dump_info_to_buffer
-		}
 		else if (strcmp(args[1], "errors") == 0) {
 			if (strm_li(s)->bind_conf->level < ACCESS_LVL_OPER) {
 				appctx->ctx.cli.msg = stats_permission_denied_msg;
@@ -1807,10 +1733,6 @@
 				else
 					si_applet_cant_put(si);
 				break;
-			case STAT_CLI_O_INFO:
-				if (stats_dump_info_to_buffer(si))
-					appctx->st0 = STAT_CLI_PROMPT;
-				break;
 			case STAT_CLI_O_ERR:	/* errors dump */
 				if (stats_dump_errors_to_buffer(si))
 					appctx->st0 = STAT_CLI_PROMPT;
@@ -1894,167 +1816,6 @@
 		si->state, req->flags, res->flags, req->buf->i, req->buf->o, res->buf->i, res->buf->o);
 }
 
-/* Dump all fields from <info> into <out> using the "show info" format (name: value) */
-static int stats_dump_info_fields(struct chunk *out, const struct field *info)
-{
-	int field;
-
-	for (field = 0; field < INF_TOTAL_FIELDS; field++) {
-		if (!field_format(info, field))
-			continue;
-
-		if (!chunk_appendf(out, "%s: ", info_field_names[field]))
-			return 0;
-		if (!stats_emit_raw_data_field(out, &info[field]))
-			return 0;
-		if (!chunk_strcat(out, "\n"))
-			return 0;
-	}
-	return 1;
-}
-
-/* Dump all fields from <info> into <out> using the "show info typed" format */
-static int stats_dump_typed_info_fields(struct chunk *out, const struct field *info)
-{
-	int field;
-
-	for (field = 0; field < INF_TOTAL_FIELDS; field++) {
-		if (!field_format(info, field))
-			continue;
-
-		if (!chunk_appendf(out, "%d.%s.%u:", field, info_field_names[field], info[INF_PROCESS_NUM].u.u32))
-			return 0;
-		if (!stats_emit_field_tags(out, &info[field], ':'))
-			return 0;
-		if (!stats_emit_typed_data_field(out, &info[field]))
-			return 0;
-		if (!chunk_strcat(out, "\n"))
-			return 0;
-	}
-	return 1;
-}
-
-/* Fill <info> with HAProxy global info. <info> is preallocated
- * array of length <len>. The length of the aray must be
- * INF_TOTAL_FIELDS. If this length is less then this value, the
- * function returns 0, otherwise, it returns 1.
- */
-int stats_fill_info(struct field *info, int len)
-{
-	unsigned int up = (now.tv_sec - start_date.tv_sec);
-	struct chunk *out = get_trash_chunk();
-
-#ifdef USE_OPENSSL
-	int ssl_sess_rate = read_freq_ctr(&global.ssl_per_sec);
-	int ssl_key_rate = read_freq_ctr(&global.ssl_fe_keys_per_sec);
-	int ssl_reuse = 0;
-
-	if (ssl_key_rate < ssl_sess_rate) {
-		/* count the ssl reuse ratio and avoid overflows in both directions */
-		ssl_reuse = 100 - (100 * ssl_key_rate + (ssl_sess_rate - 1) / 2) / ssl_sess_rate;
-	}
-#endif
-
-	if (len < INF_TOTAL_FIELDS)
-		return 0;
-
-	chunk_reset(out);
-	memset(info, 0, sizeof(*info) * len);
-
-	info[INF_NAME]                           = mkf_str(FO_PRODUCT|FN_OUTPUT|FS_SERVICE, PRODUCT_NAME);
-	info[INF_VERSION]                        = mkf_str(FO_PRODUCT|FN_OUTPUT|FS_SERVICE, HAPROXY_VERSION);
-	info[INF_RELEASE_DATE]                   = mkf_str(FO_PRODUCT|FN_OUTPUT|FS_SERVICE, HAPROXY_DATE);
-
-	info[INF_NBPROC]                         = mkf_u32(FO_CONFIG|FS_SERVICE, global.nbproc);
-	info[INF_PROCESS_NUM]                    = mkf_u32(FO_KEY, relative_pid);
-	info[INF_PID]                            = mkf_u32(FO_STATUS, pid);
-
-	info[INF_UPTIME]                         = mkf_str(FN_DURATION, chunk_newstr(out));
-	chunk_appendf(out, "%ud %uh%02um%02us", up / 86400, (up % 86400) / 3600, (up % 3600) / 60, (up % 60));
-
-	info[INF_UPTIME_SEC]                     = mkf_u32(FN_DURATION, up);
-	info[INF_MEMMAX_MB]                      = mkf_u32(FO_CONFIG|FN_LIMIT, global.rlimit_memmax);
-	info[INF_POOL_ALLOC_MB]                  = mkf_u32(0, (unsigned)(pool_total_allocated() / 1048576L));
-	info[INF_POOL_USED_MB]                   = mkf_u32(0, (unsigned)(pool_total_used() / 1048576L));
-	info[INF_POOL_FAILED]                    = mkf_u32(FN_COUNTER, pool_total_failures());
-	info[INF_ULIMIT_N]                       = mkf_u32(FO_CONFIG|FN_LIMIT, global.rlimit_nofile);
-	info[INF_MAXSOCK]                        = mkf_u32(FO_CONFIG|FN_LIMIT, global.maxsock);
-	info[INF_MAXCONN]                        = mkf_u32(FO_CONFIG|FN_LIMIT, global.maxconn);
-	info[INF_HARD_MAXCONN]                   = mkf_u32(FO_CONFIG|FN_LIMIT, global.hardmaxconn);
-	info[INF_CURR_CONN]                      = mkf_u32(0, actconn);
-	info[INF_CUM_CONN]                       = mkf_u32(FN_COUNTER, totalconn);
-	info[INF_CUM_REQ]                        = mkf_u32(FN_COUNTER, global.req_count);
-#ifdef USE_OPENSSL
-	info[INF_MAX_SSL_CONNS]                  = mkf_u32(FN_MAX, global.maxsslconn);
-	info[INF_CURR_SSL_CONNS]                 = mkf_u32(0, sslconns);
-	info[INF_CUM_SSL_CONNS]                  = mkf_u32(FN_COUNTER, totalsslconns);
-#endif
-	info[INF_MAXPIPES]                       = mkf_u32(FO_CONFIG|FN_LIMIT, global.maxpipes);
-	info[INF_PIPES_USED]                     = mkf_u32(0, pipes_used);
-	info[INF_PIPES_FREE]                     = mkf_u32(0, pipes_free);
-	info[INF_CONN_RATE]                      = mkf_u32(FN_RATE, read_freq_ctr(&global.conn_per_sec));
-	info[INF_CONN_RATE_LIMIT]                = mkf_u32(FO_CONFIG|FN_LIMIT, global.cps_lim);
-	info[INF_MAX_CONN_RATE]                  = mkf_u32(FN_MAX, global.cps_max);
-	info[INF_SESS_RATE]                      = mkf_u32(FN_RATE, read_freq_ctr(&global.sess_per_sec));
-	info[INF_SESS_RATE_LIMIT]                = mkf_u32(FO_CONFIG|FN_LIMIT, global.sps_lim);
-	info[INF_MAX_SESS_RATE]                  = mkf_u32(FN_RATE, global.sps_max);
-
-#ifdef USE_OPENSSL
-	info[INF_SSL_RATE]                       = mkf_u32(FN_RATE, ssl_sess_rate);
-	info[INF_SSL_RATE_LIMIT]                 = mkf_u32(FO_CONFIG|FN_LIMIT, global.ssl_lim);
-	info[INF_MAX_SSL_RATE]                   = mkf_u32(FN_MAX, global.ssl_max);
-	info[INF_SSL_FRONTEND_KEY_RATE]          = mkf_u32(0, ssl_key_rate);
-	info[INF_SSL_FRONTEND_MAX_KEY_RATE]      = mkf_u32(FN_MAX, global.ssl_fe_keys_max);
-	info[INF_SSL_FRONTEND_SESSION_REUSE_PCT] = mkf_u32(0, ssl_reuse);
-	info[INF_SSL_BACKEND_KEY_RATE]           = mkf_u32(FN_RATE, read_freq_ctr(&global.ssl_be_keys_per_sec));
-	info[INF_SSL_BACKEND_MAX_KEY_RATE]       = mkf_u32(FN_MAX, global.ssl_be_keys_max);
-	info[INF_SSL_CACHE_LOOKUPS]              = mkf_u32(FN_COUNTER, global.shctx_lookups);
-	info[INF_SSL_CACHE_MISSES]               = mkf_u32(FN_COUNTER, global.shctx_misses);
-#endif
-	info[INF_COMPRESS_BPS_IN]                = mkf_u32(FN_RATE, read_freq_ctr(&global.comp_bps_in));
-	info[INF_COMPRESS_BPS_OUT]               = mkf_u32(FN_RATE, read_freq_ctr(&global.comp_bps_out));
-	info[INF_COMPRESS_BPS_RATE_LIM]          = mkf_u32(FO_CONFIG|FN_LIMIT, global.comp_rate_lim);
-#ifdef USE_ZLIB
-	info[INF_ZLIB_MEM_USAGE]                 = mkf_u32(0, zlib_used_memory);
-	info[INF_MAX_ZLIB_MEM_USAGE]             = mkf_u32(FO_CONFIG|FN_LIMIT, global.maxzlibmem);
-#endif
-	info[INF_TASKS]                          = mkf_u32(0, nb_tasks_cur);
-	info[INF_RUN_QUEUE]                      = mkf_u32(0, run_queue_cur);
-	info[INF_IDLE_PCT]                       = mkf_u32(FN_AVG, idle_pct);
-	info[INF_NODE]                           = mkf_str(FO_CONFIG|FN_OUTPUT|FS_SERVICE, global.node);
-	if (global.desc)
-		info[INF_DESCRIPTION]            = mkf_str(FO_CONFIG|FN_OUTPUT|FS_SERVICE, global.desc);
-
-	return 1;
-}
-
-/* This function dumps information onto the stream interface's read buffer.
- * It returns 0 as long as it does not complete, non-zero upon completion.
- * No state is used.
- */
-static int stats_dump_info_to_buffer(struct stream_interface *si)
-{
-	struct appctx *appctx = __objt_appctx(si->end);
-
-	if (!stats_fill_info(info, INF_TOTAL_FIELDS))
-		return 0;
-
-	chunk_reset(&trash);
-
-	if (appctx->ctx.stats.flags & STAT_FMT_TYPED)
-		stats_dump_typed_info_fields(&trash, info);
-	else
-		stats_dump_info_fields(&trash, info);
-
-	if (bi_putchk(si_ic(si), &trash) == -1) {
-		si_applet_cant_put(si);
-		return 0;
-	}
-
-	return 1;
-}
-
-
 /* This is called when the stream interface is closed. For instance, upon an
  * external abort, we won't call the i/o handler anymore so we may need to
  * remove back references to the stream currently being dumped.
diff --git a/src/stats.c b/src/stats.c
index e879614..56266eb 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -74,6 +74,64 @@
 #endif
 
 
+/* These are the field names for each INF_* field position. Please pay attention
+ * to always use the exact same name except that the strings for new names must
+ * be lower case or CamelCase while the enum entries must be upper case.
+ */
+const char *info_field_names[INF_TOTAL_FIELDS] = {
+	[INF_NAME]                           = "Name",
+	[INF_VERSION]                        = "Version",
+	[INF_RELEASE_DATE]                   = "Release_date",
+	[INF_NBPROC]                         = "Nbproc",
+	[INF_PROCESS_NUM]                    = "Process_num",
+	[INF_PID]                            = "Pid",
+	[INF_UPTIME]                         = "Uptime",
+	[INF_UPTIME_SEC]                     = "Uptime_sec",
+	[INF_MEMMAX_MB]                      = "Memmax_MB",
+	[INF_POOL_ALLOC_MB]                  = "PoolAlloc_MB",
+	[INF_POOL_USED_MB]                   = "PoolUsed_MB",
+	[INF_POOL_FAILED]                    = "PoolFailed",
+	[INF_ULIMIT_N]                       = "Ulimit-n",
+	[INF_MAXSOCK]                        = "Maxsock",
+	[INF_MAXCONN]                        = "Maxconn",
+	[INF_HARD_MAXCONN]                   = "Hard_maxconn",
+	[INF_CURR_CONN]                      = "CurrConns",
+	[INF_CUM_CONN]                       = "CumConns",
+	[INF_CUM_REQ]                        = "CumReq",
+	[INF_MAX_SSL_CONNS]                  = "MaxSslConns",
+	[INF_CURR_SSL_CONNS]                 = "CurrSslConns",
+	[INF_CUM_SSL_CONNS]                  = "CumSslConns",
+	[INF_MAXPIPES]                       = "Maxpipes",
+	[INF_PIPES_USED]                     = "PipesUsed",
+	[INF_PIPES_FREE]                     = "PipesFree",
+	[INF_CONN_RATE]                      = "ConnRate",
+	[INF_CONN_RATE_LIMIT]                = "ConnRateLimit",
+	[INF_MAX_CONN_RATE]                  = "MaxConnRate",
+	[INF_SESS_RATE]                      = "SessRate",
+	[INF_SESS_RATE_LIMIT]                = "SessRateLimit",
+	[INF_MAX_SESS_RATE]                  = "MaxSessRate",
+	[INF_SSL_RATE]                       = "SslRate",
+	[INF_SSL_RATE_LIMIT]                 = "SslRateLimit",
+	[INF_MAX_SSL_RATE]                   = "MaxSslRate",
+	[INF_SSL_FRONTEND_KEY_RATE]          = "SslFrontendKeyRate",
+	[INF_SSL_FRONTEND_MAX_KEY_RATE]      = "SslFrontendMaxKeyRate",
+	[INF_SSL_FRONTEND_SESSION_REUSE_PCT] = "SslFrontendSessionReuse_pct",
+	[INF_SSL_BACKEND_KEY_RATE]           = "SslBackendKeyRate",
+	[INF_SSL_BACKEND_MAX_KEY_RATE]       = "SslBackendMaxKeyRate",
+	[INF_SSL_CACHE_LOOKUPS]              = "SslCacheLookups",
+	[INF_SSL_CACHE_MISSES]               = "SslCacheMisses",
+	[INF_COMPRESS_BPS_IN]                = "CompressBpsIn",
+	[INF_COMPRESS_BPS_OUT]               = "CompressBpsOut",
+	[INF_COMPRESS_BPS_RATE_LIM]          = "CompressBpsRateLim",
+	[INF_ZLIB_MEM_USAGE]                 = "ZlibMemUsage",
+	[INF_MAX_ZLIB_MEM_USAGE]             = "MaxZlibMemUsage",
+	[INF_TASKS]                          = "Tasks",
+	[INF_RUN_QUEUE]                      = "Run_queue",
+	[INF_IDLE_PCT]                       = "Idle_pct",
+	[INF_NODE]                           = "node",
+	[INF_DESCRIPTION]                    = "description",
+};
+
 const char *stat_field_names[ST_F_TOTAL_FIELDS] = {
 	[ST_F_PXNAME]         = "pxname",
 	[ST_F_SVNAME]         = "svname",
@@ -160,10 +218,13 @@
 	[ST_F_DSES]           = "dses",
 };
 
+/* one line of info */
+static struct field info[INF_TOTAL_FIELDS];
 /* one line of stats */
 static struct field stats[ST_F_TOTAL_FIELDS];
 
 
+
 /*
  * http_stats_io_handler()
  *     -> stats_dump_stat_to_buffer()     // same as above, but used for CSV or HTML
@@ -2813,6 +2874,175 @@
 	/* just to make gcc happy */ ;
 }
 
+/* Dump all fields from <info> into <out> using the "show info" format (name: value) */
+static int stats_dump_info_fields(struct chunk *out, const struct field *info)
+{
+	int field;
+
+	for (field = 0; field < INF_TOTAL_FIELDS; field++) {
+		if (!field_format(info, field))
+			continue;
+
+		if (!chunk_appendf(out, "%s: ", info_field_names[field]))
+			return 0;
+		if (!stats_emit_raw_data_field(out, &info[field]))
+			return 0;
+		if (!chunk_strcat(out, "\n"))
+			return 0;
+	}
+	return 1;
+}
+
+/* Dump all fields from <info> into <out> using the "show info typed" format */
+static int stats_dump_typed_info_fields(struct chunk *out, const struct field *info)
+{
+	int field;
+
+	for (field = 0; field < INF_TOTAL_FIELDS; field++) {
+		if (!field_format(info, field))
+			continue;
+
+		if (!chunk_appendf(out, "%d.%s.%u:", field, info_field_names[field], info[INF_PROCESS_NUM].u.u32))
+			return 0;
+		if (!stats_emit_field_tags(out, &info[field], ':'))
+			return 0;
+		if (!stats_emit_typed_data_field(out, &info[field]))
+			return 0;
+		if (!chunk_strcat(out, "\n"))
+			return 0;
+	}
+	return 1;
+}
+
+/* Fill <info> with HAProxy global info. <info> is preallocated
+ * array of length <len>. The length of the aray must be
+ * INF_TOTAL_FIELDS. If this length is less then this value, the
+ * function returns 0, otherwise, it returns 1.
+ */
+int stats_fill_info(struct field *info, int len)
+{
+	unsigned int up = (now.tv_sec - start_date.tv_sec);
+	struct chunk *out = get_trash_chunk();
+
+#ifdef USE_OPENSSL
+	int ssl_sess_rate = read_freq_ctr(&global.ssl_per_sec);
+	int ssl_key_rate = read_freq_ctr(&global.ssl_fe_keys_per_sec);
+	int ssl_reuse = 0;
+
+	if (ssl_key_rate < ssl_sess_rate) {
+		/* count the ssl reuse ratio and avoid overflows in both directions */
+		ssl_reuse = 100 - (100 * ssl_key_rate + (ssl_sess_rate - 1) / 2) / ssl_sess_rate;
+	}
+#endif
+
+	if (len < INF_TOTAL_FIELDS)
+		return 0;
+
+	chunk_reset(out);
+	memset(info, 0, sizeof(*info) * len);
+
+	info[INF_NAME]                           = mkf_str(FO_PRODUCT|FN_OUTPUT|FS_SERVICE, PRODUCT_NAME);
+	info[INF_VERSION]                        = mkf_str(FO_PRODUCT|FN_OUTPUT|FS_SERVICE, HAPROXY_VERSION);
+	info[INF_RELEASE_DATE]                   = mkf_str(FO_PRODUCT|FN_OUTPUT|FS_SERVICE, HAPROXY_DATE);
+
+	info[INF_NBPROC]                         = mkf_u32(FO_CONFIG|FS_SERVICE, global.nbproc);
+	info[INF_PROCESS_NUM]                    = mkf_u32(FO_KEY, relative_pid);
+	info[INF_PID]                            = mkf_u32(FO_STATUS, pid);
+
+	info[INF_UPTIME]                         = mkf_str(FN_DURATION, chunk_newstr(out));
+	chunk_appendf(out, "%ud %uh%02um%02us", up / 86400, (up % 86400) / 3600, (up % 3600) / 60, (up % 60));
+
+	info[INF_UPTIME_SEC]                     = mkf_u32(FN_DURATION, up);
+	info[INF_MEMMAX_MB]                      = mkf_u32(FO_CONFIG|FN_LIMIT, global.rlimit_memmax);
+	info[INF_POOL_ALLOC_MB]                  = mkf_u32(0, (unsigned)(pool_total_allocated() / 1048576L));
+	info[INF_POOL_USED_MB]                   = mkf_u32(0, (unsigned)(pool_total_used() / 1048576L));
+	info[INF_POOL_FAILED]                    = mkf_u32(FN_COUNTER, pool_total_failures());
+	info[INF_ULIMIT_N]                       = mkf_u32(FO_CONFIG|FN_LIMIT, global.rlimit_nofile);
+	info[INF_MAXSOCK]                        = mkf_u32(FO_CONFIG|FN_LIMIT, global.maxsock);
+	info[INF_MAXCONN]                        = mkf_u32(FO_CONFIG|FN_LIMIT, global.maxconn);
+	info[INF_HARD_MAXCONN]                   = mkf_u32(FO_CONFIG|FN_LIMIT, global.hardmaxconn);
+	info[INF_CURR_CONN]                      = mkf_u32(0, actconn);
+	info[INF_CUM_CONN]                       = mkf_u32(FN_COUNTER, totalconn);
+	info[INF_CUM_REQ]                        = mkf_u32(FN_COUNTER, global.req_count);
+#ifdef USE_OPENSSL
+	info[INF_MAX_SSL_CONNS]                  = mkf_u32(FN_MAX, global.maxsslconn);
+	info[INF_CURR_SSL_CONNS]                 = mkf_u32(0, sslconns);
+	info[INF_CUM_SSL_CONNS]                  = mkf_u32(FN_COUNTER, totalsslconns);
+#endif
+	info[INF_MAXPIPES]                       = mkf_u32(FO_CONFIG|FN_LIMIT, global.maxpipes);
+	info[INF_PIPES_USED]                     = mkf_u32(0, pipes_used);
+	info[INF_PIPES_FREE]                     = mkf_u32(0, pipes_free);
+	info[INF_CONN_RATE]                      = mkf_u32(FN_RATE, read_freq_ctr(&global.conn_per_sec));
+	info[INF_CONN_RATE_LIMIT]                = mkf_u32(FO_CONFIG|FN_LIMIT, global.cps_lim);
+	info[INF_MAX_CONN_RATE]                  = mkf_u32(FN_MAX, global.cps_max);
+	info[INF_SESS_RATE]                      = mkf_u32(FN_RATE, read_freq_ctr(&global.sess_per_sec));
+	info[INF_SESS_RATE_LIMIT]                = mkf_u32(FO_CONFIG|FN_LIMIT, global.sps_lim);
+	info[INF_MAX_SESS_RATE]                  = mkf_u32(FN_RATE, global.sps_max);
+
+#ifdef USE_OPENSSL
+	info[INF_SSL_RATE]                       = mkf_u32(FN_RATE, ssl_sess_rate);
+	info[INF_SSL_RATE_LIMIT]                 = mkf_u32(FO_CONFIG|FN_LIMIT, global.ssl_lim);
+	info[INF_MAX_SSL_RATE]                   = mkf_u32(FN_MAX, global.ssl_max);
+	info[INF_SSL_FRONTEND_KEY_RATE]          = mkf_u32(0, ssl_key_rate);
+	info[INF_SSL_FRONTEND_MAX_KEY_RATE]      = mkf_u32(FN_MAX, global.ssl_fe_keys_max);
+	info[INF_SSL_FRONTEND_SESSION_REUSE_PCT] = mkf_u32(0, ssl_reuse);
+	info[INF_SSL_BACKEND_KEY_RATE]           = mkf_u32(FN_RATE, read_freq_ctr(&global.ssl_be_keys_per_sec));
+	info[INF_SSL_BACKEND_MAX_KEY_RATE]       = mkf_u32(FN_MAX, global.ssl_be_keys_max);
+	info[INF_SSL_CACHE_LOOKUPS]              = mkf_u32(FN_COUNTER, global.shctx_lookups);
+	info[INF_SSL_CACHE_MISSES]               = mkf_u32(FN_COUNTER, global.shctx_misses);
+#endif
+	info[INF_COMPRESS_BPS_IN]                = mkf_u32(FN_RATE, read_freq_ctr(&global.comp_bps_in));
+	info[INF_COMPRESS_BPS_OUT]               = mkf_u32(FN_RATE, read_freq_ctr(&global.comp_bps_out));
+	info[INF_COMPRESS_BPS_RATE_LIM]          = mkf_u32(FO_CONFIG|FN_LIMIT, global.comp_rate_lim);
+#ifdef USE_ZLIB
+	info[INF_ZLIB_MEM_USAGE]                 = mkf_u32(0, zlib_used_memory);
+	info[INF_MAX_ZLIB_MEM_USAGE]             = mkf_u32(FO_CONFIG|FN_LIMIT, global.maxzlibmem);
+#endif
+	info[INF_TASKS]                          = mkf_u32(0, nb_tasks_cur);
+	info[INF_RUN_QUEUE]                      = mkf_u32(0, run_queue_cur);
+	info[INF_IDLE_PCT]                       = mkf_u32(FN_AVG, idle_pct);
+	info[INF_NODE]                           = mkf_str(FO_CONFIG|FN_OUTPUT|FS_SERVICE, global.node);
+	if (global.desc)
+		info[INF_DESCRIPTION]            = mkf_str(FO_CONFIG|FN_OUTPUT|FS_SERVICE, global.desc);
+
+	return 1;
+}
+
+/* This function dumps information onto the stream interface's read buffer.
+ * It returns 0 as long as it does not complete, non-zero upon completion.
+ * No state is used.
+ */
+static int stats_dump_info_to_buffer(struct stream_interface *si)
+{
+	struct appctx *appctx = __objt_appctx(si->end);
+
+	if (!stats_fill_info(info, INF_TOTAL_FIELDS))
+		return 0;
+
+	chunk_reset(&trash);
+
+	if (appctx->ctx.stats.flags & STAT_FMT_TYPED)
+		stats_dump_typed_info_fields(&trash, info);
+	else
+		stats_dump_info_fields(&trash, info);
+
+	if (bi_putchk(si_ic(si), &trash) == -1) {
+		si_applet_cant_put(si);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int cli_parse_show_info(char **args, struct appctx *appctx, void *private)
+{
+	if (strcmp(args[2], "typed") == 0)
+		appctx->ctx.stats.flags |= STAT_FMT_TYPED;
+	appctx->st2 = STAT_ST_INIT;
+	return 0;
+}
+
+
 static int cli_parse_show_stat(char **args, struct appctx *appctx, void *private)
 {
 	if (*args[2] && *args[3] && *args[4]) {
@@ -2830,6 +3060,11 @@
 	return 0;
 }
 
+static int cli_io_handler_dump_info(struct appctx *appctx)
+{
+	return stats_dump_info_to_buffer(appctx->owner);
+}
+
 /* This I/O handler runs as an applet embedded in a stream interface. It is
  * used to send raw stats over a socket.
  */
@@ -2840,6 +3075,7 @@
 
 /* register cli keywords */
 static struct cli_kw_list cli_kws = {{ },{
+	{ { "show", "info",  NULL }, "show info      : report information about the running process", cli_parse_show_info, cli_io_handler_dump_info, NULL },
 	{ { "show", "stat",  NULL }, "show stat      : report counters for each proxy and server", cli_parse_show_stat, cli_io_handler_dump_stat, NULL },
 	{{},}
 }};