MINOR: ssl/cli: replace dump/show ssl crt-list by '-n' option

The dump and show ssl crt-list commands does the same thing, they dump
the content of a crt-list, but the 'show' displays an ID in the first
column. Delete the 'dump' command so it is replaced by the 'show' one.
The old 'show' command is replaced by an '-n' option to dump the ID.
And the ID which was a pointer is replaced by a line number and placed
after colons in the filename.

Example:
  $ echo "show ssl crt-list -n kikyo.crt-list" | socat /tmp/sock1 -
  # kikyo.crt-list
  kikyo.pem.rsa:1 secure.domain.tld
  kikyo.pem.ecdsa:2 secure.domain.tld
diff --git a/doc/management.txt b/doc/management.txt
index 2aea4e0..43e3524 100644
--- a/doc/management.txt
+++ b/doc/management.txt
@@ -1595,18 +1595,6 @@
   This command is restricted and can only be issued on sockets configured for
   level "admin".
 
-dump ssl crt-list <filename>
-  Dump the content of a crt-list or a directory. Once dumped the output can be
-  used as a crt-list file.
-
-  Example:
-    echo "dump ssl crt-list localhost.crt-list" | socat /tmp/sock1 -
-    # localhost.crt-list
-    common.pem !not.test1.com *.test1.com !localhost
-    common.pem
-    ecdsa.pem [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3] localhost !www.test1.com
-    ecdsa.pem [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3]
-
 enable agent <backend>/<server>
   Resume auxiliary agent check that was temporarily stopped.
 
@@ -2582,20 +2570,22 @@
     Filename: *test.local.pem
     [...]
 
-show ssl crt-list [<filename>]
+show ssl crt-list [-n] [<filename>]
   Display the list of crt-list and directories used in the HAProxy
-  configuration. If a directory or a crt-list is specified, displays its
-  content. Does not use this command to dump your crt-list configuration as it
-  provides extra informations not compatible with the crt-list. To dump a
-  crt-list, use the "dump ssl crt-list" command instead.
+  configuration. If a filename is specified, dump the content of a crt-list or
+  a directory. Once dumped the output can be used as a crt-list file.
+  The '-n' option can be used to display the line number, which is useful when
+  combined with the 'del ssl crt-list' option when a entry is duplicated. The
+  output with the '-n' option is not compatible with the crt-list format and
+  not loadable by haproxy.
 
   Example:
-    echo "show ssl crt-list localhost.crt-list" | socat /tmp/sock1 -
+    echo "show ssl crt-list -n localhost.crt-list" | socat /tmp/sock1 -
     # localhost.crt-list
-    0x55db301c29a0 common.pem !not.test1.com *.test1.com !localhost
-    0x55db301f99e0 common.pem
-    0x7fb6f40220b0 ecdsa.pem [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3] localhost !www.test1.com
-    0x55db30277070 ecdsa.pem [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3]
+    common.pem:1 !not.test1.com *.test1.com !localhost
+    common.pem:2
+    ecdsa.pem:3 [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3] localhost !www.test1.com
+    ecdsa.pem:4 [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3]
 
 show resolvers [<resolvers section id>]
   Dump statistics for the given resolvers section, or all resolvers sections
diff --git a/include/types/ssl_sock.h b/include/types/ssl_sock.h
index f3d851d..dd286bb 100644
--- a/include/types/ssl_sock.h
+++ b/include/types/ssl_sock.h
@@ -156,6 +156,7 @@
 /* This structure is basically a crt-list or a directory */
 struct crtlist {
 	struct bind_conf_list *bind_conf; /* list of bind_conf which use this crtlist */
+	unsigned int linecount; /* number of lines */
 	struct eb_root entries;
 	struct list ord_entries; /* list to keep the line order of the crt-list file */
 	struct ebmb_node node; /* key is the filename or directory */
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index b1fdb09..282e343 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -4567,6 +4567,7 @@
 	memcpy(dir->node.key, path, strlen(path) + 1);
 	dir->entries = EB_ROOT_UNIQUE; /* it's a directory, files are unique */
 	dir->bind_conf = NULL;
+	dir->linecount = 0;
 	LIST_INIT(&dir->ord_entries);
 
 	n = scandir(path, &de_list, 0, alphasort);
@@ -4602,6 +4603,7 @@
 			}
 
 			/* directories don't use ssl_conf and filters */
+			entry->linenum = 0;
 			entry->fcount = 0;
 			entry->filters = NULL;
 			entry->ssl_conf = NULL;
@@ -4804,7 +4806,7 @@
 			goto error;
 		}
 	}
-
+	entry->linenum = linenum;
 	entry->ssl_conf = ssl_conf;
 	entry->filters = crtlist_dup_filters(&args[cur_arg], arg - cur_arg - 1);
 	entry->fcount = arg - cur_arg - 1;
@@ -4937,6 +4939,8 @@
 	if (cfgerr & ERR_CODE)
 		goto error;
 
+	newlist->linecount = linenum;
+
 	fclose(f);
 	*crtlist = newlist;
 
@@ -11155,9 +11159,9 @@
 
 		store = entry->node.key;
 		filename = store->path;
-		if (appctx->ctx.cli.i0 == 's') /* show */
-			chunk_appendf(trash, "%p ", entry);
 		chunk_appendf(trash, "%s", filename);
+		if (appctx->ctx.cli.i0 == 's') /* show */
+			chunk_appendf(trash, ":%d", entry->linenum);
 		dump_crtlist_sslconf(trash, entry->ssl_conf);
 		dump_crtlist_filters(trash, entry);
 		chunk_appendf(trash, "\n");
@@ -11179,6 +11183,7 @@
 static int cli_parse_dump_crtlist(char **args, char *payload, struct appctx *appctx, void *private)
 {
 	struct ebmb_node *lnode;
+	char *filename = NULL;
 	int mode;
 
 	if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
@@ -11186,13 +11191,20 @@
 
 	appctx->ctx.cli.p0 = NULL;
 	appctx->ctx.cli.p1 = NULL;
-	mode = (int)args[0][0]; /* 'd' or 's' */
 
-	if (mode == 'd' && !*args[3])
-		return cli_err(appctx, "'dump ssl crt-list' expects a filename or a directory\n");
+	if (*args[3] && !strcmp(args[3], "-n")) {
+		mode = 's';
+		filename = args[4];
+	} else {
+		mode = 'd';
+		filename = args[3];
+	}
 
-	if (*args[3]) {
-		lnode = ebst_lookup(&crtlists_tree, args[3]);
+	if (mode == 's' && !*args[4])
+		return cli_err(appctx, "'show ssl crt-list -n' expects a filename or a directory\n");
+
+	if (filename && *filename) {
+		lnode = ebst_lookup(&crtlists_tree, filename);
 		if (lnode == NULL)
 			return cli_err(appctx, "didn't find the specified filename\n");
 
@@ -11320,6 +11332,7 @@
 					ssl_sock_load_cert_sni(new_inst, new_inst->bind_conf);
 					HA_RWLOCK_WRUNLOCK(SNI_LOCK, &new_inst->bind_conf->sni_lock);
 				}
+				entry->linenum = ++crtlist->linecount;
 				appctx->st2 = SETCERT_ST_FIN;
 				goto end;
 		}
@@ -12722,8 +12735,7 @@
 	{ { "show", "ssl", "cert", NULL }, "show ssl cert [<certfile>] : display the SSL certificates used in memory, or the details of a <certfile>", cli_parse_show_cert, cli_io_handler_show_cert, cli_release_show_cert },
 	{ { "add", "ssl", "crt-list", NULL }, "add ssl crt-list <filename> <certfile> [options] : add a line <certfile> to a crt-list <filename>", cli_parse_add_crtlist, cli_io_handler_add_crtlist, cli_release_add_crtlist },
 	{ { "del", "ssl", "crt-list", NULL }, "del ssl crt-list <filename> <certfile[:line]> : delete a line <certfile> in a crt-list <filename>", cli_parse_del_crtlist, NULL, NULL },
-	{ { "dump", "ssl", "crt-list", NULL }, "dump ssl crt-list <filename> : dump the content of a crt-list <filename>", cli_parse_dump_crtlist, cli_io_handler_dump_crtlist, NULL },
-	{ { "show", "ssl", "crt-list", NULL }, "show ssl crt-list [<filename>] : show the list of crt-lists or the content of a crt-list <filename>", cli_parse_dump_crtlist, cli_io_handler_dump_crtlist, NULL },
+	{ { "show", "ssl", "crt-list", NULL }, "show ssl crt-list [-n] [<filename>] : show the list of crt-lists or the content of a crt-list <filename>", cli_parse_dump_crtlist, cli_io_handler_dump_crtlist, NULL },
 	{ { NULL }, NULL, NULL, NULL }
 }};