Commit Diff


commit - 2cbf96e394f7a7decbae2f8a6829b8cddd03536b
commit + f943f99c53a154c97b93aaff0c6147d40bd8de82
blob - cb93dae29f883f57ee923b60a332edcaf8749fa6
blob + d0ea33ff297130b499703d8f068c954783abcdb3
--- Makefile
+++ Makefile
@@ -1,6 +1,8 @@
 #
 PROG= nsh
 
+SUBDIR += bgpnsh
+
 .PHONY: release dist
 
 .include "nsh-version.mk"
@@ -23,11 +25,12 @@ CFLAGS?=-O
 CFLAGS+=-Wmissing-prototypes -Wformat -Wall -Wbad-function-cast -I/usr/local/include #-W -Wpointer-arith
 CPPFLAGS+=-DNSH_VERSION=${NSH_VERSION}  -DNSH_REXEC_PATH=${NSH_REXEC_PATH}
 
-SRCS=arp.c compile.c main.c genget.c commands.c stats.c kroute.c
+SRCS=arp.c compile.c main.c genget.c commands.c bgpcommands.c stats.c kroute.c
 SRCS+=ctl.c show.c if.c version.c route.c conf.c complete.c ieee80211.c
 SRCS+=bridge.c tunnel.c media.c sysctl.c passwd.c pfsync.c carp.c
-SRCS+=trunk.c who.c more.c stringlist.c utils.c sqlite3.c ppp.c
-SRCS+=nopt.c pflow.c wg.c nameserver.c ndp.c umb.c utf8.c
+SRCS+=trunk.c who.c more.c stringlist.c utils.c sqlite3.c ppp.c prompt.c
+SRCS+=nopt.c pflow.c wg.c nameserver.c ndp.c umb.c utf8.c cmdargs.c ctlargs.c
+SRCS+=helpcommands.c makeargv.c
 CLEANFILES+=compile.c
 LDADD=-lutil -ledit -ltermcap -lsqlite3 -L/usr/local/lib #-static
 
@@ -55,3 +58,4 @@ dist: clean
 	rm ${.CURDIR}/nsh-dist.txt.new
 
 .include <bsd.prog.mk>
+.include <bsd.subdir.mk>
blob - /dev/null
blob + 1f466aefdc939449c3b12b9646e9c5a6a53a1353 (mode 644)
--- /dev/null
+++ bgpcommands.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2008-2009 Chris Cappuccio <chris@nmedia.net>
+ * Copyright (c) 2023 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>	/* MAXHOSTNAMELEN */
+#include <net/if.h>	/* IFNAMSIZ */
+
+#include <sys/types.h>
+
+#include <limits.h>
+#include <stdio.h>
+
+#include "externs.h"
+#include "commands.h"
+#include "ctl.h"
+
+char bgpd_socket_path[PATH_MAX];
+
+#define BGPSOCK "-s", bgpd_socket_path
+
+struct prot1 bgcs[] = {
+	{ "announced",  "All announced networks",
+	    { BGPCTL,  BGPSOCK, "network", "show", OPT, NULL } },
+	{ "interfaces", "Interface states",
+	    { BGPCTL,  BGPSOCK, "show", "interfaces", NULL } },
+	{ "nexthop",	"BGP nexthop routes",
+	    { BGPCTL,  BGPSOCK, "show", "nexthop", NULL } },
+	{ "summary",	"Neighbor session states and counters",
+	    { BGPCTL,  BGPSOCK, "show", "summary", OPT, NULL } },
+	{ "rib",	"Routing Information Base",
+	    { BGPCTL, BGPSOCK, "show",  "rib", OPT, OPT, OPT, NULL } },
+	{ "neighbor",	"Detailed peer",
+	    { BGPCTL, BGPSOCK, "show",  "neighbor", REQ, OPT, NULL } },
+	{ "ip",		"IP BGP",
+	    { BGPCTL, BGPSOCK, "show",  "ip", "bgp", OPT, OPT, OPT, NULL } },
+	{ 0, 0, { 0 } }
+};
+
+/* Initialize the globally stored BGPD socket path. */
+void
+init_bgpd_socket_path(int rtable)
+{
+	snprintf(bgpd_socket_path, sizeof(bgpd_socket_path),
+	    "%s.%d", BGPD_SOCKET_PATH, rtable);
+}
blob - /dev/null
blob + 66fa671ac5ac8390f2891dc49b5bc3f1b2b477f3 (mode 644)
--- /dev/null
+++ bgpnsh/.gitignore
@@ -0,0 +1 @@
+obj/**
blob - /dev/null
blob + d4f2f7232f6db50ce16ca840c67378a609085eb5 (mode 644)
--- /dev/null
+++ bgpnsh/Makefile
@@ -0,0 +1,32 @@
+#
+PROG= bgpnsh
+
+.PATH=${.CURDIR}/..
+
+.include "../nsh-version.mk"
+
+.if ${NSH_RELEASE} != Yes
+DEBUG?=-O0 -g
+.endif
+
+.if make(install)
+DESTDIR?=/usr/local
+BINDIR?=/bin
+MANDIR?=/man/man
+.endif
+
+CFLAGS+=-Wmissing-prototypes -Wformat -Wall -Wbad-function-cast
+CPPFLAGS+=-DNSH_VERSION=${NSH_VERSION}
+
+SRCS=bgpnsh.c compile.c bgpcommands.c complete.c genget.c more.c \
+	stringlist.c utf8.c stubs.c cmdargs.c ctlargs.c prompt.c \
+	helpcommands.c makeargv.c
+CLEANFILES+=compile.c
+LDADD=-lutil -ledit -ltermcap
+
+MAN=bgpnsh.8
+
+compile.c: compile.sh
+	sh ${.CURDIR}/../compile.sh
+
+.include <bsd.prog.mk>
blob - /dev/null
blob + 526a5088941e553ced275539ec25a922a24d03d6 (mode 644)
--- /dev/null
+++ bgpnsh/bgpnsh.8
@@ -0,0 +1,64 @@
+
+.\" Copyright (c) 2023 Stefan Sperling
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate$
+.Dt BGPNSH 1
+.Os
+.Sh NAME
+.Nm bgpnsh
+.Nd BGP Looking Glass Network Shell
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+.Nm
+is a command interpreter intended for interactive use as a BGP
+Looking Glass shell for routers running
+.Xr bgpd 8 .
+.Pp
+.Nm
+is an alternative to
+.Xr bgplgsh 1
+with a user interface that matches the user interface of
+.Xr nsh 8 .
+.Pp
+All functionality of
+.Nm
+is also available in
+.Xr nsh 8 .
+Unlike
+.Xr nsh 8 ,
+.Nm
+restricts users to commands which obtain BGP routing information for
+diagnostic purposes.
+.Pp
+.Nm
+will usually be configured as the login shell for dedicated user accounts
+which are used to obtain BGP routing information from the system.
+See
+.Xr shells 5
+for more information.
+.Sh ENVIRONMENT
+.Bl -tag -width BGPNSH_SOCKET
+.It Ev BGPNSH_SOCKET
+Sets an alternative path to the restricted control socket of
+.Xr bgpd 8 .
+The default path is
+.Pa /var/www/run/bgpd.rsock .
+.Sh SEE ALSO
+.Xr bgplgsh 1 ,
+.Xr shells 5 ,
+.Xr bgpd 8 ,
+.Xr bgplg 8 ,
+.Xr nsh 8
blob - /dev/null
blob + fe3730444452dde0891c8c67fdb741b605e6f00c (mode 644)
--- /dev/null
+++ bgpnsh/bgpnsh.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2023 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>	/* MAXHOSTNAMELEN */
+#include <net/if.h>	/* IFNAMSIZ */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include "../externs.h"
+#include "../editing.h"
+#include "../commands.h"
+#include "../ctl.h"
+
+#define BGPNSH_SOCKET "/var/www/run/bgpd.rsock" /* restricted socket */
+
+History *histc = NULL;
+History *histi = NULL;
+HistEvent ev;
+EditLine *elc = NULL;
+EditLine *eli = NULL;
+EditLine *elp = NULL;
+char *cursor_pos = NULL;
+
+pid_t	child;
+
+void sigalarm(int signo)
+{
+	if (child != -1) {
+		kill(child, SIGKILL);
+	}
+}
+
+int editing = 1, config_mode = 0;
+int cli_rtable;
+int bridge;
+size_t Intlist_nitems = 0, Bridgelist_nitems = 0;
+int priv;
+
+char hbuf[MAXHOSTNAMELEN];	/* host name */
+char ifname[IFNAMSIZ];		/* interface name */
+
+struct intlist *whichlist;
+
+extern struct prot1 bgcs[];
+
+struct prot prots[] = {
+	{ "bgp",	bgcs },
+};
+
+Menu showlist[] = {
+	{ "bgp",	"BGP information",
+	   CMPL(ta) (char **)bgcs, sizeof(struct prot1), 0, 4, pr_prot1 },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static int
+showcmd(int argc, char **argv)
+{
+	Menu *s;	/* pointer to current command */
+
+	if (argc < 2) {
+		show_help(argc, argv);
+		return 0;
+	}
+
+	/*
+	 * Validate show argument
+	 */
+	s = (Menu *) genget(argv[1], (char **) showlist, sizeof(Menu));
+	if (s == 0) {
+		printf("%% Invalid argument %s\n", argv[1]);
+		return 0;
+	} else if (Ambiguous(s)) {
+		printf("%% Ambiguous argument %s\n", argv[1]);
+		return 0;
+	}
+	if (((s->minarg + 2) > argc) || ((s->maxarg + 2) < argc)) {
+		printf("%% Wrong number of argument%s to 'show %s' command"
+		    " (min %i, max %i)\n", argc <= 2 ? "" : "s", s->name,
+		    s->minarg, s->maxarg);
+		return 0;
+	}
+
+	(*s->handler)(argc, argv, NULL);
+	return 0;
+}
+
+int
+quit(void)
+{
+	printf("%% Session terminated.\n");
+	exit(0);
+	return 0;
+}
+
+Command cmdtab[] = {
+	{ "show",	"Show system information",
+	    CMPL(ta) (char **)showlist, sizeof(Menu), showcmd,	0, 0, 0, 0 },
+	{ "quit",	"Close current connection",
+	    CMPL0 0, 0, quit,		0, 0, 0, 0 },
+	{ "help",	0,
+	    CMPL(c) 0, 0, help,		0, 0, 0, 0 },
+	{ 0,		0,		CMPL0 0, 0, 0,			0, 0, 0, 0 }
+};
+size_t cmdtab_nitems = nitems(cmdtab);
+
+Command *
+getcmd(char *name)
+{
+	Command *cm;
+
+	cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command));
+	return cm;
+}
+
+void
+command(void)
+{
+	Command  *c;
+	u_int num;
+
+	for (;;) {
+		const char *buf;
+		cursor_pos = NULL;
+
+		if ((buf = el_gets(elc, &num)) == NULL || num == 0)
+			break;
+
+		if (buf[--num]  == '\n') {
+			if (num == 0)
+				break;
+		}
+		if (num >= sizeof(line)) {
+			printf("%% Input exceeds permitted length\n");
+			break;
+		}
+		memcpy(line, buf, (size_t)num);
+		line[num] = '\0';
+		history(histc, &ev, H_ENTER, buf);
+
+		if (line[0] == 0)
+			break;
+		makeargv();
+		if (margv[0] == 0) {
+			break;
+		}
+
+		c = getcmd(margv[0]);
+		if (Ambiguous(c)) {
+			printf("%% Ambiguous command\n");
+			continue;
+		}
+		if (c == 0) {
+			int val = el_burrito(elc, margc, margv);
+			if (val)
+				printf("%% Invalid command\n");
+			continue;
+		}
+		if (NO_ARG(margv[0]) && ! c->nocmd) {
+			printf("%% Invalid command: %s %s\n", margv[0],
+			    margv[1]);
+			continue;
+		}
+
+		if ((*c->handler) (margc, margv, 0))
+			break;
+	}
+}
+
+int
+main(int argc, char *argv[])
+{
+	char *socket_path;
+
+	if (argc != 1) {
+		fprintf(stderr, "usage: %s\n", getprogname());
+		return 1;
+	}
+
+	inithist();
+	initedit();
+
+	if (unveil(BGPCTL, "x") == -1)
+		err(1, "unveil %s", BGPCTL);
+
+	if (unveil(NULL, NULL) == -1)
+		err(1, "unveil");
+
+	if (pledge("stdio tty proc exec", NULL) == -1)
+		err(1, "pledge");
+
+	socket_path = getenv("BGPNSH_SOCKET");
+	if (socket_path == NULL)
+		socket_path = BGPNSH_SOCKET;
+	if (strlcpy(bgpd_socket_path, socket_path, sizeof(bgpd_socket_path)) >=
+	    sizeof(bgpd_socket_path))
+		err(1, "bgpd socket path too long");
+
+	command();
+
+	return 0;
+}
blob - /dev/null
blob + 452b80c34d3ec3eb9123284e8a249c1af6874380 (mode 644)
--- /dev/null
+++ bgpnsh/stubs.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2023 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* These functions are stubbed out in bgpnsh but required for linking. */
+
+#include "../stringlist.h"
+
+int is_bridge(int, char *);
+int db_select_rtable_rtables(StringList *);
+
+int
+is_bridge(int s, char *brdg)
+{
+	return 0;
+}
+
+int
+db_select_rtable_rtables(StringList *words)
+{
+	return -1;
+}
blob - eebb73667f75dda726d8e045bee3e25554254690
blob + 4a9419a0ddac0891c65b10ea7ab7e5150a51e051
--- commands.c
+++ commands.c
@@ -68,22 +68,11 @@
 #include "sysctl.h"
 #include "ctl.h"
 
-char prompt[128];
-char saved_prompt[sizeof(prompt)];
-
-char line[1024];
-char saveline[1024];
-int  margc;
 char hname[HSIZE];
-static char hbuf[MAXHOSTNAMELEN];	/* host name */
-static char ifname[IFNAMSIZ];		/* interface name */
+char hbuf[MAXHOSTNAMELEN];	/* host name */
+char ifname[IFNAMSIZ];		/* interface name */
 struct intlist *whichlist;
 
-#define NARGS  sizeof(line)/2		/* max arguments in char line[] */
-char	*margv[NARGS];			/* argv storage */
-size_t	cursor_argc;			/* location of cursor in margv */
-size_t	cursor_argo;			/* offset of cursor margv[cursor_argc] */
-
 pid_t	child;
 
 static int	disable(void);
@@ -93,14 +82,12 @@ static int	doconfig(int, char**);
 static int	exitconfig(int, char**);
 int		rtable(int, char**);
 int		group(int, char**);
-static int	nsh_setrtable(int);
 static int	pr_routes(int, char **);
 static int	pr_routes6(int, char **);
 static int	pr_arp(int, char **);
 static int	pr_ndp(int, char **);
 static int	pr_sadb(int, char **);
 static int	pr_kernel(int, char **);
-static int	pr_prot1(int, char **);
 static int	pr_dhcp(int, char **);
 static int	pr_conf(int, char **);
 static int	pr_s_conf(int, char **);
@@ -109,7 +96,6 @@ static int	pr_conf_diff(int, char **);
 static int	show_hostname(int, char **);
 static int	wr_startup(void);
 static int	wr_conf(char *);
-static int	show_help(int, char **);
 static int	sysctlhelp(int, char **, char **, int);
 static int	flush_pf(char *);
 static int	flush_help(void);
@@ -135,9 +121,7 @@ static int	int_manual(char *, int, int, char **);
 static int	int_shell(char *, int, int, char **);
 static int	int_help(void);
 static int	int_exit(void);
-static int	el_burrito(EditLine *, int, char **);
 static int	hostname(int, char **);
-static int	help(int, char**);
 static int	manual(int, char**);
 static int	nocmd(int, char **);
 static int	docmd(int, char **);
@@ -152,9 +136,7 @@ static int	telnet(int, char*[]);
 static int 	nreboot(void);
 static int 	halt(void);
 static int 	powerdown(void);
-static Command *getcmd(char *);
 static void	pf_stats(void);
-static void	sigalarm(int);
 
 #include "commands.h"
 
@@ -165,6 +147,230 @@ void sigalarm(int blahfart)
 	}
 }
 
+static struct fpf {
+	char *name;
+	char *help;
+	char *cmd;
+	char *arg;
+} fpfs[] = {
+	{ "all",	"all PF elements",	PFCTL,	"-Fall" },
+	{ "nat",	"NAT rules",		PFCTL,	"-Fnat" },
+	{ "queue",	"queue rules",		PFCTL,	"-Fqueue" },
+	{ "filter",	"filter rules",		PFCTL,	"-Frules" },
+	{ "states",	"NAT/filter states",	PFCTL,	"-Fstate" },
+	{ "stats",	"PF statistics",	PFCTL,	"-Finfo" },
+	{ "tables",	"PF address tables",	PFCTL,	"-FTables" },
+	{ 0, 0, 0, 0 }
+};
+
+static struct stt {
+	char *name;
+	char *help;
+	void (*handler) ();
+} stts[] = {
+	{ "ip",		"Internet Protocol",			ip_stats },
+	{ "ah",		"Authentication Header",		ah_stats },
+	{ "esp",	"Encapsulated Security Payload",	esp_stats },
+	{ "tcp",	"Transmission Control Protocol",	tcp_stats },
+	{ "udp",	"Unreliable Datagram Protocol",		udp_stats },
+	{ "icmp",	"Internet Control Message Protocol",	icmp_stats },
+	{ "igmp",	"Internet Group Management Protocol",	igmp_stats },
+	{ "ipcomp",	"IP Compression",			ipcomp_stats },
+	{ "route",	"Routing",				rt_stats },
+	{ "carp",	"Common Address Redundancy Protocol",	carp_stats },
+	{ "mbuf",	"Packet memory buffer",			mbpr },
+	{ "pf",		"Packet Filter",			pf_stats },
+	{ 0,		0,					0 }
+};
+
+
+struct prot1 oscs[] = {
+	{ "fib",	"Forward Information Base",
+	    { OSPFCTL, "show", "fib", OPT, OPT, NULL } },
+	{ "database",	"Link State Database",
+	    { OSPFCTL, "show", "database", OPT, OPT, NULL } },
+	{ "interfaces",	"Interface",
+	    { OSPFCTL, "show", "interfaces", OPT, NULL } },
+	{ "neighbor",	"Neighbor",
+	    { OSPFCTL, "show", "neighbor", OPT, NULL } },
+	{ "rib",	"Routing Information Base",
+	    { OSPFCTL, "show", "rib", OPT, NULL } },
+	{ "summary",	"Summary",
+	    { OSPFCTL, "show", "summary", NULL } },
+	{ 0, 0, { 0 } }
+};
+
+struct prot1 os6cs[] = {
+	{ "fib",        "Forward Information Base",
+	    { OSPF6CTL, "show", "fib", OPT, OPT, NULL } },
+	{ "database",   "Link State Database",
+	    { OSPF6CTL, "show", "database", OPT, OPT, NULL } },
+	{ "interfaces", "Interface",
+	    { OSPF6CTL, "show", "interfaces", OPT, NULL } },
+	{ "neighbor",   "Neighbor",
+	    { OSPF6CTL, "show", "neighbor", OPT, NULL } },
+	{ "rib",        "Routing Information Base",
+	    { OSPF6CTL, "show", "rib", OPT, NULL } },
+	{ "summary",    "Summary",
+	    { OSPF6CTL, "show", "summary", NULL } },
+	{ 0, 0, { 0 } }
+};
+
+struct prot1 pfcs[] = {
+	{ "all",           "all pf info except fingerprints and interfaces", 
+            { PFCTL, "-sall", NULL, NULL, NULL, NULL } },
+	{ "anchors",       "currently loaded anchors in main pf ruleset", 
+            { PFCTL, "-sAnchors", NULL, NULL, NULL } },	
+        { "info ",         "pf filter statistics, counters and tracking",
+            { PFCTL, "-sinfo", "-v", NULL, NULL, NULL } },
+        { "labels",        "per rule stats (bytes, packets and states)",        
+            { PFCTL, "-slabels", NULL, NULL, NULL, NULL } },
+        { "memory",        "current pf pool memory hard limit",
+            { PFCTL, "-smemory", NULL, NULL, NULL, NULL } },
+	{ "queues",        "currently loaded pf queue definition", 
+            { PFCTL, "-squeue", "-v", NULL, NULL, NULL } },
+	{ "rules",         "active pf firewall rule",
+            { PFCTL, "-srules", NULL, NULL, NULL, NULL } },
+	{ "sources",       "contents of the pf source tracking table", 
+            { PFCTL, "-sSources", NULL, NULL, NULL, NULL } },
+	{ "states",        "contents of the pf state table",
+            { PFCTL, "-sstates", NULL, NULL, NULL, NULL } },
+        { "tables",        "pf table",
+            { PFCTL, "-sTables", NULL, NULL, NULL, NULL } },
+	{ "timeouts",      "current pf global timeout", 
+            { PFCTL, "-stimeouts", NULL, NULL, NULL, NULL } },
+	{ "osfingerprint", "pf Operating System fingerprint", 
+            { PFCTL, "-sosfp", NULL, NULL, NULL, NULL } },
+	{ "interfaces",    "pf usable interfaces/ interface group", 
+            { PFCTL, "-sInterfaces", NULL, NULL, NULL, NULL } },
+	{ 0, 0, { 0 } }                                                         
+};
+struct prot1 eics[] = {
+	{ "interfaces",	"Interface",
+	    { EIGRPCTL, "show", "interfaces", OPT, OPT, NULL } },
+	{ "neighbor",	"Neighbor",
+	    { EIGRPCTL, "show", "neighbor", OPT, OPT, NULL } },
+	{ "topology",	"Topology",
+	    { EIGRPCTL, "show", "topology", OPT, OPT, NULL } },
+	{ "traffic",	"Traffic",
+	    { EIGRPCTL, "show", "traffic", OPT, OPT, NULL } },
+	{ 0, 0, { 0 } }
+};
+
+struct prot1 rics[] = {
+	{ "fib",        "Forward Information Base",
+	    { RIPCTL, "show", "fib", OPT, NULL } },
+	{ "interfaces", "Interfaces",
+	    { RIPCTL, "show", "interfaces", NULL } },
+	{ "neighbor",   "Neighbor",
+	    { RIPCTL, "show", "neighbor", NULL } },
+	{ "rib",        "Routing Information Base",
+	    { RIPCTL, "show", "rib", NULL } },
+	{ 0, 0, { 0 } }
+};
+
+struct prot1 lics[] = {
+	{ "fib",        "Forward Information Base",
+	    { LDPCTL, "show", "fib", OPT, NULL } },
+	{ "interfaces", "Interfaces",
+	    { LDPCTL, "show", "interfaces", NULL } },
+	{ "neighbor",   "Neighbors",
+	    { LDPCTL, "show", "neighbor", NULL } },
+	{ "lib",        "Label Information Base",
+	    { LDPCTL, "show", "lib", NULL } },
+	{ "discovery",	"Adjacencies",
+	    { LDPCTL, "show", "discovery", NULL } },
+	{ "l2vpn",	"Pseudowire",
+	    { LDPCTL, "show", "l2vpn", OPT, NULL } },
+	{ 0, 0, { 0 } }
+};
+
+struct prot1 iscs[] = {
+	{ "flows",	"Display IPsec flows",
+	    { IPSECCTL, "-sf", NULL } },
+	{ "sadb",	"Display SADB",
+	    { IPSECCTL, "-ss", NULL } },
+	{ 0, 0, { 0 } }
+};
+
+struct prot1 ikcs[] = {
+	{ "monitor",	"Monitor internal iked messages",
+	    { IKECTL, "monitor", NULL } },
+	{ 0, 0, { 0 } }
+};
+
+struct prot1 dvcs[] = {
+	{ "igmp",       "Internet Group Message Protocol",
+	    { DVMRPCTL, "show", "igmp", NULL } },
+	{ "interfaces", "Interfaces",
+	    { DVMRPCTL, "show", "interfaces", OPT, NULL } },
+	{ "mfc",        "Multicast Forwarding Cache",
+	    { DVMRPCTL, "show", "mfc", OPT, NULL } },
+	{ "neighbor",   "Neighbor",
+	    { DVMRPCTL, "show", "neighbor", OPT, NULL } },
+	{ "rib",        "Routing Information Base",
+	    { DVMRPCTL, "show", "rib", OPT, NULL } },
+	{ "summary",    "Summary",
+	    { DVMRPCTL, "show", "summary", NULL } },
+        { 0, 0, { 0 } }
+};
+
+struct prot1 rlcs[] = {
+	{ "hosts",      "hosts",
+	    { RELAYCTL, "show", "hosts", NULL } },
+	{ "redirects",  "redirects",
+	    { RELAYCTL, "show", "redirects", NULL } },
+	{ "status",     "status",
+	    { RELAYCTL, "show", "relays", NULL } },
+	{ "sessions",   "sessions",
+	    { RELAYCTL, "show", "sessions", NULL } },
+	{ "summary",    "summary",
+	    { RELAYCTL, "show", "summary", NULL } },
+	{ 0, 0, { 0 } }
+};
+
+struct prot1 smcs[] = {
+	{ "queue",	"envelopes in queue",
+	    { SMTPCTL, "show", "queue", NULL } },
+	{ "runqueue",	"envelopes scheduled for delivery",
+	    { SMTPCTL, "show", "runqueue", NULL } },
+	{ "stats",	"runtime statistics",
+	    { SMTPCTL, "show", "stats", NULL } },
+	{ 0, 0, { 0 } }
+};
+
+struct prot1 dhcs[] = {
+	{ "leases",	"leases", { 0 } },
+	{ 0, 0, { 0 } }
+};
+
+struct prot1 ldcs[] = {
+	{ "stats",	"statistics counters",
+	    { LDAPCTL, "stats", NULL } },
+	{ 0, 0, { 0 } }
+};
+
+extern struct prot1 bgcs[];
+
+/* show yyy zzz */
+struct prot prots[] = {
+	{ "bgp",	bgcs },
+	{ "ospf",	oscs },
+	{ "ospf6",	os6cs },
+	{ "pf",		pfcs },
+	{ "eigrp",	eics },
+	{ "rip",	rics },
+	{ "ike",	ikcs },
+	{ "ipsec",	iscs },
+	{ "ldp",	lics },
+	{ "dvmrp",	dvcs },
+	{ "relay",	rlcs },
+	{ "smtp",	smcs },
+	{ "ldap",	ldcs },
+	{ 0,		0 }
+};
+
+
 /*
  * Quit command
  */
@@ -343,27 +549,6 @@ done:
 	if (unlink(outpath) == -1)
 		printf("%% unlink %s: %s\n", outpath, strerror(errno));
 	return(error);
-}
-
-static int
-show_help(int argc, char **argv)
-{
-	Menu *s; /* pointer to current command */
-	u_int z = 0;
-
-	printf("%% Commands may be abbreviated.\n");
-	printf("%% 'show' commands are:\n\n");
-
-	for (s = showlist; s->name; s++) {
-		if (strlen(s->name) > z)
-			z = strlen(s->name);
-	}
-
-	for (s = showlist; s->name; s++) {
-		if (s->help)
-			printf("  %-*s  %s\n", z, s->name, s->help);
-	}
-	return 0;
 }
 
 /*
@@ -1801,74 +1986,13 @@ getcmd(char *name)
 }
 
 void
-makeargv()
-{
-	char	*cp, *cp2, *base, c;
-	char	**argp = margv;
-
-	margc = 0;
-	cp = line;
-	if (*cp == '!') {	/* Special case shell escape */
-		/* save for shell command */
-		strlcpy(saveline, line, sizeof(saveline));
-
-		*argp++ = "!";	/* No room in string to get this */
-		margc++;
-		cp++;
-	}
-	while ((c = *cp)) {
-		int inquote = 0;
-		while (isspace((unsigned char)c))
-			c = *++cp;
-		if (c == '\0')
-			break;
-		*argp++ = cp;
-		cursor_argc = margc += 1;
-		base = cp;
-		for (cursor_argo = 0, cp2 = cp; c != '\0';
-		    cursor_argo = (cp + 1) - base, c = *++cp) {
-			if (inquote) {
-				if (c == inquote) {
-					inquote = 0;
-					continue;
-				}
-			} else {
-				if (c == '\\') {
-					if ((c = *++cp) == '\0')
-						break;
-				} else if (c == '"') {
-					inquote = '"';
-					continue;
-				} else if (c == '\'') {
-					inquote = '\'';
-					continue;
-				} else if (isspace((unsigned char)c)) {
-					cursor_argo = 0;
-					break;
-				}
-			}
-			*cp2++ = c;
-		}
-		*cp2 = '\0';
-		if (c == '\0') {
-			cursor_argc--;
-			break;
-		}
-		cp++;
-	}
-	*argp++ = 0;
-	if (cursor_pos == line) {
-		cursor_argc = 0;
-		cursor_argo = 0;
-	}
-}
-
-void
 command()
 {
 	Command  *c;
 	u_int num;
 
+	init_bgpd_socket_path(getrtable());
+
 	if (editing) {
 		inithist();
 		initedit();
@@ -1950,46 +2074,6 @@ command()
 }
 
 /*
- * Help command.
- */
-static int
-help(int argc, char **argv)
-{
-	Command *c;
-
-	if (argc == 1) {
-		u_int z = 0;
-
-		printf("%% Commands may be abbreviated.\n");
-		printf("%% Commands are:\n\n");
-
-		for (c = cmdtab; c->name; c++)
-			if (((c->needpriv && priv) || !c->needpriv)
-			    && strlen(c->name) > z)
-				z = strlen(c->name);
-		for (c = cmdtab; c->name; c++) {
-			if (c->help &&
-			    ((c->needpriv && priv) || !c->needpriv) &&
-			    ((c->needconfig && config_mode) || !c->needconfig))
-				printf("  %-*s  %s\n", z, c->name, c->help);
-		}
-		return 0;
-	}
-	while (--argc > 0) {
-		char *arg;
-		arg = *++argv;
-		c = getcmd(arg);
-		if (Ambiguous(c))
-			printf("%% Ambiguous help command %s\n", arg);
-		else if (c == (Command *)0)
-			printf("%% Invalid help command %s\n", arg);
-		else
-			printf("%% %s: %s\n", arg, c->help);
-	}
-	return 0;
-}
-
-/*
  * Manual command.
  */
 
@@ -2117,28 +2201,6 @@ int show_hostname(int argc, char **argv)
 		printf("%s\n", hbuf);
 
 	return 0;
-}
-
-int
-nsh_setrtable(int rtableid)
-{
-	int cur_rtable;
-	errno = 0;
-
-	cur_rtable = getrtable();
-	if (cur_rtable != rtableid && setrtable(rtableid) < 0)
-		switch(errno) {
-		case EINVAL:
-			printf("%% rtable %d not initialized\n",
-			    cli_rtable);
-			break;
-		case EPERM:
-			printf("%% nsh not running as root?\n");
-			break;
-		default:
-			printf("%% setrtable failed: %d\n", errno);
-		}
-	return(errno);
 }
 
 /*
@@ -2516,91 +2578,6 @@ group(int argc, char **argv)
 	}
 
 	return 0;
-}
-
-/*
- * cmd, multiple args
- *
- * If no error occurs then return the program's exit code (>= 0).
- * Return -1 on error to run the program or if the program was
- * terminated in an abnormal way, such as being killed by a signal.
- */
-int
-cmdargs(char *cmd, char *arg[])
-{
-	return cmdargs_output(cmd, arg, -1, -1);
-}
-
-/*
- * cmd, multiple args, capture stdout and stderr output
- *
- * If no error occurs then return the program's exit code (>= 0).
- * Return -1 on error to run the program or if the program was
- * terminated in an abnormal way, such as being killed by a signal.
- */
-int
-cmdargs_output(char *cmd, char *arg[], int stdoutfd, int stderrfd)
-{
-	sig_t sigint, sigquit, sigchld;
-	int status = -1;
-
-	sigint = signal(SIGINT, SIG_IGN);
-	sigquit = signal(SIGQUIT, SIG_IGN);
-	sigchld = signal(SIGCHLD, SIG_DFL);
-
-	switch (child = fork()) {
-		case -1:
-			printf("%% fork failed: %s\n", strerror(errno));
-			return -1;
-
-		case 0:
-		{
-			char *shellp = cmd;
-
-			signal(SIGQUIT, SIG_DFL);
-			signal(SIGINT, SIG_DFL);
-			signal(SIGCHLD, SIG_DFL);
-
-			if (cli_rtable != 0 && nsh_setrtable(cli_rtable))
-				_exit(0);
-
-			if (stdoutfd != -1) {
-				if (stdoutfd != STDOUT_FILENO &&
-				    dup2(stdoutfd, STDOUT_FILENO) == -1) {
-					printf("%% dup2: %s\n",
-					    strerror(errno));
-					_exit(0);
-				}
-			}
-			if (stderrfd != -1) {
-				if (stderrfd != STDERR_FILENO &&
-				    dup2(stderrfd, STDERR_FILENO) == -1) {
-					printf("%% dup2 failed: %s\n",
-					    strerror(errno));
-					_exit(0);
-				}
-			}
-
-			execv(shellp, arg);
-			printf("%% execv failed: %s\n", strerror(errno));
-			_exit(127); /* same as what ksh(1) would do here */
-		}
-			break;
-		default:
-			signal(SIGALRM, sigalarm);
-			wait(&status);  /* Wait for cmd to complete */
-			if (WIFEXITED(status)) /* normal exit? */
-				status = WEXITSTATUS(status); /* exit code */
-			break;
-	}
-
-	signal(SIGINT, sigint);
-	signal(SIGQUIT, sigquit);
-	signal(SIGCHLD, sigchld);
-	signal(SIGALRM, SIG_DFL);
-	child = -1;
-
-	return status;
 }
 
 /*
@@ -2709,32 +2686,6 @@ flush_history(void)
 	initedit();
 
 	return(0);
-}
-
-void
-gen_help(char **x, char *cmdprefix, char *descrsuffix, int szstruct)
-{
-	/* only for structures starting with char *name; char *help; !! */
-	char **y = x;
-	struct ghs *ghs;
-	int z = 0;
-
-	printf("%% Arguments may be abbreviated\n\n");
-
-	while (*y != 0) {
-		if (strlen(*y) > z)
-			z = strlen(*y);
-		y = (char **)((char *)y + szstruct);
-	}
-
-	while (*x != 0) {
-		ghs = (struct ghs *)x;
-		if (ghs->help)
-			printf("  %s %-*s %s %s\n", cmdprefix, z, *x,
-			    ghs->help, descrsuffix);
-		x = (char **)((char *)x + szstruct);
-	}
-	return;
 }
 
 /*
@@ -2781,6 +2732,8 @@ cmdrc(char rcname[FILENAME_MAX])
 	unsigned int lnum;	/* line number */
 	u_int	z = 0;		/* max length of cmdtab argument */
 
+	init_bgpd_socket_path(getrtable());
+
 	if ((rcfile = fopen(rcname, "r")) == 0) {
 		printf("%% Unable to open %s: %s\n", rcname, strerror(errno));
 		return 1;
@@ -2900,90 +2853,7 @@ p_argv(int argc, char **argv)
 	return;
 }
 
-/*
- * for the purpose of interface handler routines, 1 here is failure and
- * 0 is success
- */
 int
-el_burrito(EditLine *el, int argc, char **argv)
-{
-	char *colon;
-	int val;
-
-	if (!editing)	/* Nothing to parse, fail */
-		return(1);
-
-	/*
-	 * el_parse will always return a non-error status if someone specifies
-	 * argv[0] with a colon.  The idea of the colon is to allow host-
-	 * specific commands, which is really only useful in .editrc, so
-	 * it is invalid here.
-	 */
-	colon = strchr(argv[0], ':');
-	if (colon)
-		return(1);
-
-	val = el_parse(el, argc, (const char **)argv);
-
-	if (val == 0)
-		return(0);
-	else
-		return(1);
-}
-
-char *
-cprompt(void)
-{
-	int pr;
-	char tmp[4];
-
-	if (cli_rtable)
-		snprintf(tmp, sizeof(tmp), "%d", cli_rtable);
-
-	gethostname(hbuf, sizeof(hbuf));
-	pr = priv | cli_rtable | config_mode;
-	snprintf(prompt, sizeof(prompt), "%s%s%s%s%s%s%s%s%s/", hbuf,
-	    pr ? "(" : "",
-	    config_mode ? "config" : "",
-	    config_mode && priv ? "-" : "",
-	    priv ? "p" : "",
-	    (( priv && cli_rtable) || (config_mode && cli_rtable)) ? "-" : "",
-	    cli_rtable ? "rtable " : "", cli_rtable ? tmp : "",
-	    pr ?")" : "");
-
-	return(prompt);
-}
-
-char *
-iprompt(void)
-{
-	gethostname(hbuf, sizeof(hbuf));
-	snprintf(prompt, sizeof(prompt), "%s(%s-%s)/", hbuf,
-	    bridge ? "bridge" : "interface", ifname);
-
-	return(prompt);
-}
-
-char *
-pprompt(void)
-{
-	return(prompt);
-}
-
-static void
-setprompt(const char *s)
-{
-	strlcpy(saved_prompt, prompt, sizeof(saved_prompt));
-	strlcpy(prompt, s, sizeof(prompt));
-}
-
-static void
-restoreprompt(void)
-{
-	strlcpy(prompt, saved_prompt, sizeof(prompt));
-}
-
-int
 wr_startup(void)
 {
 	char *argv[] = { SAVESCRIPT, NSHRC_TEMP, NULL };
@@ -3453,109 +3323,8 @@ pf_stats(void)
 
 	cmdargs(PFCTL, argv);
 	return;
-}
-
-int
-pr_prot1(int argc, char **argv)
-{
-	struct prot1 *x;
-	struct prot *prot;
-	char *args[NOPTFILL] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
-	char **fillargs;
-	char prefix[64];
-
-	/* loop protocol list to find table pointer */
-	prot = (struct prot *) genget(argv[1], (char **)prots,
-	    sizeof(struct prot));
-	if (prot == 0) {
-		printf("%% Internal error - Invalid argument %s\n", argv[1]);
-		return 0;
-	} else if (Ambiguous(prot)) {
-		printf("%% Internal error - Ambiguous argument %s\n", argv[1]);
-		return 0;
-	}
-
-	snprintf(prefix, sizeof(prefix), "show %s", prot->name);
-
-	/* no clue? we can help */
-	if (argc < 3 || argv[2][0] == '?') {
-		gen_help((char **)prot->table, prefix, "information",
-		    sizeof(struct prot1));
-		return 0;
-	}
-	x = (struct prot1 *) genget(argv[2], (char **)prot->table,
-	    sizeof(struct prot1));
-	if (x == 0) {
-		printf("%% Invalid argument %s\n", argv[2]);
-		return 0;
-	} else if (Ambiguous(x)) {
-		printf("%% Ambiguous argument %s\n", argv[2]);
-		return 0;
-	}
-
-	fillargs = step_optreq(x->args, args, argc, argv, 3);
-	if (fillargs == NULL)
-		return 0;
-
-	cmdargs(fillargs[0], fillargs);
-
-	return 1;
 }
 
-char **
-step_optreq(char **xargs, char **args, int argc, char **argv, int skip)
-{
-	int i;
-	int fill = 0;	/* total fillable arguments */
-	int flc = 0;	/* number of filled arguments */
-
-	/* count fillable arguments */
-	for (i = 0; i < NOPTFILL - 1; i++) {
-		if (xargs[i] == OPT || xargs[i] == REQ)
-			fill++;
-		if (xargs[i] == NULL)
-			break;
-	}
-
-	if (argc - skip > fill) {
-		printf("%% Superfluous argument: %s\n", argv[skip + fill]);
-		return NULL;
-	}
-
-	/* copy xargs to args, replace OPT/REQ args with argv past skip */
-	for (i = 0; i < NOPTFILL - 2; i++) {
-		if (xargs[i] == NULL) {
-			args[i] = NULL;
-			if (i > 1)
-			/*
-			 * all **args passed must have at least two arguments
-			 * and a terminating NULL.  the point of this check
-			 * is to allow the first two arguments to be NULL but
-			 * still fill in fillargs[x] with corresponding NULL
-			 */
-				break;
-		}
-		if (xargs[i] == OPT || xargs[i] == REQ) {
-			/* copy from argv to args */
-			if (argc - skip - flc > 0) {
-				args[i] = argv[skip + flc];
-				flc++;
-			} else if (xargs[i] == REQ) {
-				printf("%% Missing required argument\n");
-				return NULL;
-			} else {
-				args[i] = NULL;
-				break;
-			}
-		} else {
-			/* copy from xargs to args */
-			args[i] = xargs[i];
-		}
-	}
-
-	return(args);
-}
-
 int
 pr_dhcp(int argc, char **argv)
 {
blob - 264b9b5372a9039445ca747b326559f4b291a05f
blob + 538228794818b95a085bd5e3aa46337a017832b2
--- commands.h
+++ commands.h
@@ -14,42 +14,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-static struct fpf {
-	char *name;
-	char *help;
-	char *cmd;
-	char *arg;
-} fpfs[] = {
-	{ "all",	"all PF elements",	PFCTL,	"-Fall" },
-	{ "nat",	"NAT rules",		PFCTL,	"-Fnat" },
-	{ "queue",	"queue rules",		PFCTL,	"-Fqueue" },
-	{ "filter",	"filter rules",		PFCTL,	"-Frules" },
-	{ "states",	"NAT/filter states",	PFCTL,	"-Fstate" },
-	{ "stats",	"PF statistics",	PFCTL,	"-Finfo" },
-	{ "tables",	"PF address tables",	PFCTL,	"-FTables" },
-	{ 0, 0, 0, 0 }
-};
-
-static struct stt {
-	char *name;
-	char *help;
-	void (*handler) ();
-} stts[] = {
-	{ "ip",		"Internet Protocol",			ip_stats },
-	{ "ah",		"Authentication Header",		ah_stats },
-	{ "esp",	"Encapsulated Security Payload",	esp_stats },
-	{ "tcp",	"Transmission Control Protocol",	tcp_stats },
-	{ "udp",	"Unreliable Datagram Protocol",		udp_stats },
-	{ "icmp",	"Internet Control Message Protocol",	icmp_stats },
-	{ "igmp",	"Internet Group Management Protocol",	igmp_stats },
-	{ "ipcomp",	"IP Compression",			ipcomp_stats },
-	{ "route",	"Routing",				rt_stats },
-	{ "carp",	"Common Address Redundancy Protocol",	carp_stats },
-	{ "mbuf",	"Packet memory buffer",			mbpr },
-	{ "pf",		"Packet Filter",			pf_stats },
-	{ 0,		0,					0 }
-};
-
 struct prot1 {
 	char *name;
 	char *help;
@@ -61,204 +25,17 @@ struct prot {
 	struct prot1 *table;
 };
 
-struct prot1 bgcs[] = {
-	{ "announced",  "All announced networks",
-	    { BGPCTL,  "network", "show", OPT, NULL } },
-	{ "interfaces", "Interface states",
-	    { BGPCTL,  "show", "interfaces", NULL } },
-	{ "nexthop",	"BGP nexthop routes",
-	    { BGPCTL,  "show", "nexthop", NULL } },
-	{ "summary",	"Neighbor session states and counters",
-	    { BGPCTL,  "show", "summary", OPT, NULL } },
-	{ "rib",	"Routing Information Base",
-	    { BGPCTL, "show",  "rib", OPT, OPT, OPT, NULL } },
-	{ "neighbor",	"Detailed peer",
-	    { BGPCTL, "show",  "neighbor", REQ, OPT, NULL } },
-	{ "ip",		"IP BGP",
-	    { BGPCTL, "show",  "ip", "bgp", OPT, OPT, OPT, NULL } },
-	{ 0, 0, { 0 } }
-};
-
-struct prot1 oscs[] = {
-	{ "fib",	"Forward Information Base",
-	    { OSPFCTL, "show", "fib", OPT, OPT, NULL } },
-	{ "database",	"Link State Database",
-	    { OSPFCTL, "show", "database", OPT, OPT, NULL } },
-	{ "interfaces",	"Interface",
-	    { OSPFCTL, "show", "interfaces", OPT, NULL } },
-	{ "neighbor",	"Neighbor",
-	    { OSPFCTL, "show", "neighbor", OPT, NULL } },
-	{ "rib",	"Routing Information Base",
-	    { OSPFCTL, "show", "rib", OPT, NULL } },
-	{ "summary",	"Summary",
-	    { OSPFCTL, "show", "summary", NULL } },
-	{ 0, 0, { 0 } }
-};
-
-struct prot1 os6cs[] = {
-	{ "fib",        "Forward Information Base",
-	    { OSPF6CTL, "show", "fib", OPT, OPT, NULL } },
-	{ "database",   "Link State Database",
-	    { OSPF6CTL, "show", "database", OPT, OPT, NULL } },
-	{ "interfaces", "Interface",
-	    { OSPF6CTL, "show", "interfaces", OPT, NULL } },
-	{ "neighbor",   "Neighbor",
-	    { OSPF6CTL, "show", "neighbor", OPT, NULL } },
-	{ "rib",        "Routing Information Base",
-	    { OSPF6CTL, "show", "rib", OPT, NULL } },
-	{ "summary",    "Summary",
-	    { OSPF6CTL, "show", "summary", NULL } },
-	{ 0, 0, { 0 } }
-};
-
-struct prot1 pfcs[] = {
-	{ "all",           "all pf info except fingerprints and interfaces", 
-            { PFCTL, "-sall", NULL, NULL, NULL, NULL } },
-	{ "anchors",       "currently loaded anchors in main pf ruleset", 
-            { PFCTL, "-sAnchors", NULL, NULL, NULL } },	
-        { "info ",         "pf filter statistics, counters and tracking",
-            { PFCTL, "-sinfo", "-v", NULL, NULL, NULL } },
-        { "labels",        "per rule stats (bytes, packets and states)",        
-            { PFCTL, "-slabels", NULL, NULL, NULL, NULL } },
-        { "memory",        "current pf pool memory hard limit",
-            { PFCTL, "-smemory", NULL, NULL, NULL, NULL } },
-	{ "queues",        "currently loaded pf queue definition", 
-            { PFCTL, "-squeue", "-v", NULL, NULL, NULL } },
-	{ "rules",         "active pf firewall rule",
-            { PFCTL, "-srules", NULL, NULL, NULL, NULL } },
-	{ "sources",       "contents of the pf source tracking table", 
-            { PFCTL, "-sSources", NULL, NULL, NULL, NULL } },
-	{ "states",        "contents of the pf state table",
-            { PFCTL, "-sstates", NULL, NULL, NULL, NULL } },
-        { "tables",        "pf table",
-            { PFCTL, "-sTables", NULL, NULL, NULL, NULL } },
-	{ "timeouts",      "current pf global timeout", 
-            { PFCTL, "-stimeouts", NULL, NULL, NULL, NULL } },
-	{ "osfingerprint", "pf Operating System fingerprint", 
-            { PFCTL, "-sosfp", NULL, NULL, NULL, NULL } },
-	{ "interfaces",    "pf usable interfaces/ interface group", 
-            { PFCTL, "-sInterfaces", NULL, NULL, NULL, NULL } },
-	{ 0, 0, { 0 } }                                                         
-};
-struct prot1 eics[] = {
-	{ "interfaces",	"Interface",
-	    { EIGRPCTL, "show", "interfaces", OPT, OPT, NULL } },
-	{ "neighbor",	"Neighbor",
-	    { EIGRPCTL, "show", "neighbor", OPT, OPT, NULL } },
-	{ "topology",	"Topology",
-	    { EIGRPCTL, "show", "topology", OPT, OPT, NULL } },
-	{ "traffic",	"Traffic",
-	    { EIGRPCTL, "show", "traffic", OPT, OPT, NULL } },
-	{ 0, 0, { 0 } }
-};
-
-struct prot1 rics[] = {
-	{ "fib",        "Forward Information Base",
-	    { RIPCTL, "show", "fib", OPT, NULL } },
-	{ "interfaces", "Interfaces",
-	    { RIPCTL, "show", "interfaces", NULL } },
-	{ "neighbor",   "Neighbor",
-	    { RIPCTL, "show", "neighbor", NULL } },
-	{ "rib",        "Routing Information Base",
-	    { RIPCTL, "show", "rib", NULL } },
-	{ 0, 0, { 0 } }
-};
-
-struct prot1 lics[] = {
-	{ "fib",        "Forward Information Base",
-	    { LDPCTL, "show", "fib", OPT, NULL } },
-	{ "interfaces", "Interfaces",
-	    { LDPCTL, "show", "interfaces", NULL } },
-	{ "neighbor",   "Neighbors",
-	    { LDPCTL, "show", "neighbor", NULL } },
-	{ "lib",        "Label Information Base",
-	    { LDPCTL, "show", "lib", NULL } },
-	{ "discovery",	"Adjacencies",
-	    { LDPCTL, "show", "discovery", NULL } },
-	{ "l2vpn",	"Pseudowire",
-	    { LDPCTL, "show", "l2vpn", OPT, NULL } },
-	{ 0, 0, { 0 } }
-};
-
-struct prot1 iscs[] = {
-	{ "flows",	"Display IPsec flows",
-	    { IPSECCTL, "-sf", NULL } },
-	{ "sadb",	"Display SADB",
-	    { IPSECCTL, "-ss", NULL } },
-	{ 0, 0, { 0 } }
-};
-
-struct prot1 ikcs[] = {
-	{ "monitor",	"Monitor internal iked messages",
-	    { IKECTL, "monitor", NULL } },
-	{ 0, 0, { 0 } }
-};
-
-struct prot1 dvcs[] = {
-	{ "igmp",       "Internet Group Message Protocol",
-	    { DVMRPCTL, "show", "igmp", NULL } },
-	{ "interfaces", "Interfaces",
-	    { DVMRPCTL, "show", "interfaces", OPT, NULL } },
-	{ "mfc",        "Multicast Forwarding Cache",
-	    { DVMRPCTL, "show", "mfc", OPT, NULL } },
-	{ "neighbor",   "Neighbor",
-	    { DVMRPCTL, "show", "neighbor", OPT, NULL } },
-	{ "rib",        "Routing Information Base",
-	    { DVMRPCTL, "show", "rib", OPT, NULL } },
-	{ "summary",    "Summary",
-	    { DVMRPCTL, "show", "summary", NULL } },
-        { 0, 0, { 0 } }
-};
-
-struct prot1 rlcs[] = {
-	{ "hosts",      "hosts",
-	    { RELAYCTL, "show", "hosts", NULL } },
-	{ "redirects",  "redirects",
-	    { RELAYCTL, "show", "redirects", NULL } },
-	{ "status",     "status",
-	    { RELAYCTL, "show", "relays", NULL } },
-	{ "sessions",   "sessions",
-	    { RELAYCTL, "show", "sessions", NULL } },
-	{ "summary",    "summary",
-	    { RELAYCTL, "show", "summary", NULL } },
-	{ 0, 0, { 0 } }
-};
-
-struct prot1 smcs[] = {
-	{ "queue",	"envelopes in queue",
-	    { SMTPCTL, "show", "queue", NULL } },
-	{ "runqueue",	"envelopes scheduled for delivery",
-	    { SMTPCTL, "show", "runqueue", NULL } },
-	{ "stats",	"runtime statistics",
-	    { SMTPCTL, "show", "stats", NULL } },
-	{ 0, 0, { 0 } }
-};
-
-struct prot1 dhcs[] = {
-	{ "leases",	"leases", { 0 } },
-	{ 0, 0, { 0 } }
-};
-
-struct prot1 ldcs[] = {
-	{ "stats",	"statistics counters",
-	    { LDAPCTL, "stats", NULL } },
-	{ 0, 0, { 0 } }
-};
-
-/* show yyy zzz */
-struct prot prots[] = {
-	{ "bgp",	bgcs },
-	{ "ospf",	oscs },
-	{ "ospf6",	os6cs },
-	{ "pf",		pfcs },
-	{ "eigrp",	eics },
-	{ "rip",	rics },
-	{ "ike",	ikcs },
-	{ "ipsec",	iscs },
-	{ "ldp",	lics },
-	{ "dvmrp",	dvcs },
-	{ "relay",	rlcs },
-	{ "smtp",	smcs },
-	{ "ldap",	ldcs },
-	{ 0,		0 }
-};
+#define BGPD_SOCKET_PATH "/var/run/bgpd.sock"
+extern char bgpd_socket_path[PATH_MAX];
+void init_bgpd_socket_path(int);
+extern struct prot prots[];
+int show_help(int, char **);
+Command *getcmd(char *);
+extern Menu showlist[];
+void makeargv(void);
+extern pid_t child;
+extern int	nsh_setrtable(int);
+extern void	sigalarm(int);
+extern char hbuf[MAXHOSTNAMELEN];
+extern char ifname[IFNAMSIZ];
+int	help(int, char**);
blob - /dev/null
blob + 7d771aecb5d74acb2b75f635b6d2b242448eb42a (mode 644)
--- /dev/null
+++ cmdargs.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2008-2009 Chris Cappuccio <chris@nmedia.net>
+ * Copyright (c) 2023 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>	/* MAXHOSTNAMELEN */
+#include <net/if.h>	/* IFNAMSIZ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "externs.h"
+#include "commands.h"
+
+/*
+ * cmd, multiple args
+ *
+ * If no error occurs then return the program's exit code (>= 0).
+ * Return -1 on error to run the program or if the program was
+ * terminated in an abnormal way, such as being killed by a signal.
+ */
+int
+cmdargs(char *cmd, char *arg[])
+{
+	return cmdargs_output(cmd, arg, -1, -1);
+}
+
+/*
+ * cmd, multiple args, capture stdout and stderr output
+ *
+ * If no error occurs then return the program's exit code (>= 0).
+ * Return -1 on error to run the program or if the program was
+ * terminated in an abnormal way, such as being killed by a signal.
+ */
+int
+cmdargs_output(char *cmd, char *arg[], int stdoutfd, int stderrfd)
+{
+	sig_t sigint, sigquit, sigchld;
+	int status = -1;
+
+	sigint = signal(SIGINT, SIG_IGN);
+	sigquit = signal(SIGQUIT, SIG_IGN);
+	sigchld = signal(SIGCHLD, SIG_DFL);
+
+	switch (child = fork()) {
+		case -1:
+			printf("%% fork failed: %s\n", strerror(errno));
+			return -1;
+
+		case 0:
+		{
+			char *shellp = cmd;
+
+			signal(SIGQUIT, SIG_DFL);
+			signal(SIGINT, SIG_DFL);
+			signal(SIGCHLD, SIG_DFL);
+
+			if (cli_rtable != 0 && nsh_setrtable(cli_rtable))
+				_exit(0);
+
+			if (stdoutfd != -1) {
+				if (stdoutfd != STDOUT_FILENO &&
+				    dup2(stdoutfd, STDOUT_FILENO) == -1) {
+					printf("%% dup2: %s\n",
+					    strerror(errno));
+					_exit(0);
+				}
+			}
+			if (stderrfd != -1) {
+				if (stderrfd != STDERR_FILENO &&
+				    dup2(stderrfd, STDERR_FILENO) == -1) {
+					printf("%% dup2 failed: %s\n",
+					    strerror(errno));
+					_exit(0);
+				}
+			}
+
+			execv(shellp, arg);
+			printf("%% execv failed: %s\n", strerror(errno));
+			_exit(127); /* same as what ksh(1) would do here */
+		}
+			break;
+		default:
+			signal(SIGALRM, sigalarm);
+			wait(&status);  /* Wait for cmd to complete */
+			if (WIFEXITED(status)) /* normal exit? */
+				status = WEXITSTATUS(status); /* exit code */
+			break;
+	}
+
+	signal(SIGINT, sigint);
+	signal(SIGQUIT, sigquit);
+	signal(SIGCHLD, sigchld);
+	signal(SIGALRM, SIG_DFL);
+	child = -1;
+
+	return status;
+}
+
+int
+nsh_setrtable(int rtableid)
+{
+	int ret = 0;
+
+	if (getrtable() == rtableid)
+		return 0;
+
+	if (setrtable(rtableid) < 0) {
+		ret = errno;
+		switch(errno) {
+		case EINVAL:
+			printf("%% rtable %d not initialized\n",
+			    cli_rtable);
+			break;
+		case EPERM:
+			printf("%% nsh not running as root?\n");
+			break;
+		default:
+			printf("%% setrtable failed: %d\n", errno);
+		}
+	} else
+		init_bgpd_socket_path(rtableid);
+
+	return(ret);
+}
blob - 5e3fe1c55c3a61150359610b85098421e3d2cb8e
blob + 1aa4e516adf58328b4cf0e36ccae19bbe005a6cc
--- complete.c
+++ complete.c
@@ -1012,3 +1012,34 @@ endedit()
 		eli = NULL;
 	}
 }
+
+/*
+ * for the purpose of interface handler routines, 1 here is failure and
+ * 0 is success
+ */
+int
+el_burrito(EditLine *el, int argc, char **argv)
+{
+	char *colon;
+	int val;
+
+	if (!editing)	/* Nothing to parse, fail */
+		return(1);
+
+	/*
+	 * el_parse will always return a non-error status if someone specifies
+	 * argv[0] with a colon.  The idea of the colon is to allow host-
+	 * specific commands, which is really only useful in .editrc, so
+	 * it is invalid here.
+	 */
+	colon = strchr(argv[0], ':');
+	if (colon)
+		return(1);
+
+	val = el_parse(el, argc, (const char **)argv);
+
+	if (val == 0)
+		return(0);
+	else
+		return(1);
+}
blob - 136e119c84cf7769ae95dad3ae5cf92c014581d5
blob + e9b851d07ca29dd0a429191bc48990f82b492690
--- editing.h
+++ editing.h
@@ -8,3 +8,5 @@ extern History *histi;		/* interface() editline(3) sta
 extern char	*cursor_pos;	/* cursor position we're looking for */
 extern size_t	cursor_argc;	/* location of cursor in margv */
 extern size_t	cursor_argo;	/* offset of cursor in margv[cursor_argc] */
+
+int	el_burrito(EditLine *, int, char **);
blob - 0be9d4e399ef96e55a54cac6c8dd39ed4b847d08
blob + 610184e1adf628ff1d5a11f25b77b38f302ad923
--- externs.h
+++ externs.h
@@ -26,6 +26,7 @@ struct rtdump {
 extern char *__progname;	/* duh */
 extern char *vers;		/* the version of nsh */
 extern char saveline[1024];	/* command line */
+#define NARGS  (sizeof(line)/2)	/* max arguments in char line[] */
 extern char line[1024];		/* command line for makeargv() */
 extern int  margc;		/* makeargv() arg count */
 extern char *margv[];		/* makeargv() args */
@@ -147,7 +148,13 @@ extern char metricnames[];
 
 /* ctl.c declarations moved to ctl.h */
 
+/* cmdargs.c */
+int cmdargs_output(char *, char **, int, int);
+int cmdargs(char *, char **);
+int nsh_setrtable(int);
+
 /* commands.c */
+extern pid_t child;
 #define NOPTFILL	7
 #define DEFAULT_EDITOR	"/usr/bin/vi"
 #define NSHRC_TEMP	"/var/run/nshrc"
@@ -169,15 +176,20 @@ extern char metricnames[];
 #define DHCPLEASES	"/var/db/dhcpd.leases"
 #endif
 int quit(void);
+void sigalarm(int);
 void command(void);
-char **step_optreq(char **, char **, int, char **, int);
 int argvtostring(int, char **, char *, int);
 int cmdrc(char rcname[FILENAME_MAX]);
-int cmdargs_output(char *, char **, int, int);
-int cmdargs(char *, char **);
+
+/* prompt.c */
 char *iprompt(void);
 char *cprompt(void);
 char *pprompt(void);
+void setprompt(const char *);
+void restoreprompt(void);
+extern char prompt[128];
+extern char saved_prompt[sizeof(prompt)];
+
 int group (int, char **);
 void gen_help(char **, char *, char *, int);
 void makeargv(void);
@@ -546,3 +558,7 @@ void show_umb(int, char *, FILE *);
 int mbs2ws(wchar_t **, size_t *, const char *);
 #endif
 int mbsavis(char**, int *, const char *);
+
+/* ctlargs.c */
+int pr_prot1(int, char **);
+char **step_optreq(char **, char **, int, char **, int);
blob - /dev/null
blob + 5d373722a7134a484dfb1355223c8f59b95898cd (mode 644)
--- /dev/null
+++ ctlargs.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2008 Chris Cappuccio <chris@nmedia.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>	/* MAXHOSTNAMELEN */
+#include <net/if.h>	/* IFNAMSIZ */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+#include "externs.h"
+#include "commands.h"
+#include "ctl.h"
+
+int
+pr_prot1(int argc, char **argv)
+{
+	struct prot1 *x;
+	struct prot *prot;
+	char *args[NOPTFILL] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+	char **fillargs;
+	char prefix[64];
+
+	/* loop protocol list to find table pointer */
+	prot = (struct prot *) genget(argv[1], (char **)prots,
+	    sizeof(struct prot));
+	if (prot == 0) {
+		printf("%% Internal error - Invalid argument %s\n", argv[1]);
+		return 0;
+	} else if (Ambiguous(prot)) {
+		printf("%% Internal error - Ambiguous argument %s\n", argv[1]);
+		return 0;
+	}
+
+	snprintf(prefix, sizeof(prefix), "show %s", prot->name);
+
+	/* no clue? we can help */
+	if (argc < 3 || argv[2][0] == '?') {
+		gen_help((char **)prot->table, prefix, "information",
+		    sizeof(struct prot1));
+		return 0;
+	}
+	x = (struct prot1 *) genget(argv[2], (char **)prot->table,
+	    sizeof(struct prot1));
+	if (x == 0) {
+		printf("%% Invalid argument %s\n", argv[2]);
+		return 0;
+	} else if (Ambiguous(x)) {
+		printf("%% Ambiguous argument %s\n", argv[2]);
+		return 0;
+	}
+
+	fillargs = step_optreq(x->args, args, argc, argv, 3);
+	if (fillargs == NULL)
+		return 0;
+
+	cmdargs(fillargs[0], fillargs);
+
+	return 1;
+}
+
+char **
+step_optreq(char **xargs, char **args, int argc, char **argv, int skip)
+{
+	int i;
+	int fill = 0;	/* total fillable arguments */
+	int flc = 0;	/* number of filled arguments */
+
+	/* count fillable arguments */
+	for (i = 0; i < NOPTFILL - 1; i++) {
+		if (xargs[i] == OPT || xargs[i] == REQ)
+			fill++;
+		if (xargs[i] == NULL)
+			break;
+	}
+
+	if (argc - skip > fill) {
+		printf("%% Superfluous argument: %s\n", argv[skip + fill]);
+		return NULL;
+	}
+
+	/* copy xargs to args, replace OPT/REQ args with argv past skip */
+	for (i = 0; i < NOPTFILL - 2; i++) {
+		if (xargs[i] == NULL) {
+			args[i] = NULL;
+			if (i > 1)
+			/*
+			 * all **args passed must have at least two arguments
+			 * and a terminating NULL.  the point of this check
+			 * is to allow the first two arguments to be NULL but
+			 * still fill in fillargs[x] with corresponding NULL
+			 */
+				break;
+		}
+		if (xargs[i] == OPT || xargs[i] == REQ) {
+			/* copy from argv to args */
+			if (argc - skip - flc > 0) {
+				args[i] = argv[skip + flc];
+				flc++;
+			} else if (xargs[i] == REQ) {
+				printf("%% Missing required argument\n");
+				return NULL;
+			} else {
+				args[i] = NULL;
+				break;
+			}
+		} else {
+			/* copy from xargs to args */
+			args[i] = xargs[i];
+		}
+	}
+
+	return(args);
+}
blob - /dev/null
blob + 9564ad11cfdf44c8f81f31ff2f0d694bd6248954 (mode 644)
--- /dev/null
+++ helpcommands.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2002-2008 Chris Cappuccio <chris@nmedia.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>	/* MAXHOSTNAMELEN */
+#include <net/if.h>	/* IFNAMSIZ */
+
+#include <sys/types.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "externs.h"
+#include "commands.h"
+
+int
+show_help(int argc, char **argv)
+{
+	Menu *s; /* pointer to current command */
+	u_int z = 0;
+
+	printf("%% Commands may be abbreviated.\n");
+	printf("%% 'show' commands are:\n\n");
+
+	for (s = showlist; s->name; s++) {
+		if (strlen(s->name) > z)
+			z = strlen(s->name);
+	}
+
+	for (s = showlist; s->name; s++) {
+		if (s->help)
+			printf("  %-*s  %s\n", z, s->name, s->help);
+	}
+	return 0;
+}
+
+void
+gen_help(char **x, char *cmdprefix, char *descrsuffix, int szstruct)
+{
+	/* only for structures starting with char *name; char *help; !! */
+	char **y = x;
+	struct ghs *ghs;
+	int z = 0;
+
+	printf("%% Arguments may be abbreviated\n\n");
+
+	while (*y != 0) {
+		if (strlen(*y) > z)
+			z = strlen(*y);
+		y = (char **)((char *)y + szstruct);
+	}
+
+	while (*x != 0) {
+		ghs = (struct ghs *)x;
+		if (ghs->help)
+			printf("  %s %-*s %s %s\n", cmdprefix, z, *x,
+			    ghs->help, descrsuffix);
+		x = (char **)((char *)x + szstruct);
+	}
+	return;
+}
+
+/*
+ * Help command.
+ */
+int
+help(int argc, char **argv)
+{
+	Command *c;
+
+	if (argc == 1) {
+		u_int z = 0;
+
+		printf("%% Commands may be abbreviated.\n");
+		printf("%% Commands are:\n\n");
+
+		for (c = cmdtab; c->name; c++)
+			if (((c->needpriv && priv) || !c->needpriv)
+			    && strlen(c->name) > z)
+				z = strlen(c->name);
+		for (c = cmdtab; c->name; c++) {
+			if (c->help &&
+			    ((c->needpriv && priv) || !c->needpriv) &&
+			    ((c->needconfig && config_mode) || !c->needconfig))
+				printf("  %-*s  %s\n", z, c->name, c->help);
+		}
+		return 0;
+	}
+	while (--argc > 0) {
+		char *arg;
+		arg = *++argv;
+		c = getcmd(arg);
+		if (Ambiguous(c))
+			printf("%% Ambiguous help command %s\n", arg);
+		else if (c == (Command *)0)
+			printf("%% Invalid help command %s\n", arg);
+		else
+			printf("%% %s: %s\n", arg, c->help);
+	}
+	return 0;
+}
blob - /dev/null
blob + a4984bcc41ea04e1e693647e0d98fe6a2f50308a (mode 644)
--- /dev/null
+++ makeargv.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2002-2008 Chris Cappuccio <chris@nmedia.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "externs.h"
+#include "editing.h"
+
+char line[1024];
+char saveline[1024];
+int  margc;
+
+char	*margv[NARGS];			/* argv storage */
+size_t	cursor_argc;			/* location of cursor in margv */
+size_t	cursor_argo;			/* offset of cursor margv[cursor_argc] */
+
+void
+makeargv(void)
+{
+	char	*cp, *cp2, *base, c;
+	char	**argp = margv;
+
+	margc = 0;
+	cp = line;
+	if (*cp == '!') {	/* Special case shell escape */
+		/* save for shell command */
+		strlcpy(saveline, line, sizeof(saveline));
+
+		*argp++ = "!";	/* No room in string to get this */
+		margc++;
+		cp++;
+	}
+	while ((c = *cp)) {
+		int inquote = 0;
+		while (isspace((unsigned char)c))
+			c = *++cp;
+		if (c == '\0')
+			break;
+		*argp++ = cp;
+		cursor_argc = margc += 1;
+		base = cp;
+		for (cursor_argo = 0, cp2 = cp; c != '\0';
+		    cursor_argo = (cp + 1) - base, c = *++cp) {
+			if (inquote) {
+				if (c == inquote) {
+					inquote = 0;
+					continue;
+				}
+			} else {
+				if (c == '\\') {
+					if ((c = *++cp) == '\0')
+						break;
+				} else if (c == '"') {
+					inquote = '"';
+					continue;
+				} else if (c == '\'') {
+					inquote = '\'';
+					continue;
+				} else if (isspace((unsigned char)c)) {
+					cursor_argo = 0;
+					break;
+				}
+			}
+			*cp2++ = c;
+		}
+		*cp2 = '\0';
+		if (c == '\0') {
+			cursor_argc--;
+			break;
+		}
+		cp++;
+	}
+	*argp++ = 0;
+	if (cursor_pos == line) {
+		cursor_argc = 0;
+		cursor_argo = 0;
+	}
+}
blob - /dev/null
blob + a5c39ddcf37cedf5347166188640b610e796ba30 (mode 644)
--- /dev/null
+++ prompt.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2008-2009 Chris Cappuccio <chris@nmedia.net>
+ * Copyright (c) 2023 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>	/* MAXHOSTNAMELEN */
+#include <net/if.h>	/* IFNAMSIZ */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "externs.h"
+#include "commands.h"
+
+char prompt[128];
+char saved_prompt[sizeof(prompt)];
+
+char *
+cprompt(void)
+{
+	int pr;
+	char tmp[4];
+
+	if (cli_rtable)
+		snprintf(tmp, sizeof(tmp), "%d", cli_rtable);
+
+	gethostname(hbuf, sizeof(hbuf));
+	pr = priv | cli_rtable | config_mode;
+	snprintf(prompt, sizeof(prompt), "%s%s%s%s%s%s%s%s%s/", hbuf,
+	    pr ? "(" : "",
+	    config_mode ? "config" : "",
+	    config_mode && priv ? "-" : "",
+	    priv ? "p" : "",
+	    (( priv && cli_rtable) || (config_mode && cli_rtable)) ? "-" : "",
+	    cli_rtable ? "rtable " : "", cli_rtable ? tmp : "",
+	    pr ?")" : "");
+
+	return(prompt);
+}
+
+char *
+iprompt(void)
+{
+	gethostname(hbuf, sizeof(hbuf));
+	snprintf(prompt, sizeof(prompt), "%s(%s-%s)/", hbuf,
+	    bridge ? "bridge" : "interface", ifname);
+
+	return(prompt);
+}
+
+char *
+pprompt(void)
+{
+	return(prompt);
+}
+
+void
+setprompt(const char *s)
+{
+	strlcpy(saved_prompt, prompt, sizeof(saved_prompt));
+	strlcpy(prompt, s, sizeof(prompt));
+}
+
+void
+restoreprompt(void)
+{
+	strlcpy(prompt, saved_prompt, sizeof(prompt));
+}