commit - 15a2fabe4d49f7c280b90dcce141c15804dbc37f
commit + bd030151f607f80ab726bd272be914feda51c4a5
blob - 0ab38bf23486728192a964f13a9d9d33e842b254
blob + 60a25858fc624dd0a79a85c65b918cdbf21efa9c
--- Makefile
+++ Makefile
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 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 hashtable.c mantab.c
+SRCS+=helpcommands.c makeargv.c hashtable.c mantab.c findprog.c
CLEANFILES+=compile.c mantab.c
LDADD=-lutil -ledit -ltermcap
blob - 2a3c298673f93f97a419f91e4124069c9e698f95
blob + bcf87e1d7524857c6f43950fbea021e464704975
--- bgpnsh/bgpnsh.c
+++ bgpnsh/bgpnsh.c
};
size_t cmdtab_nitems = nitems(cmdtab);
+Command extcmdtab[] = {
+ { NULL, NULL, CMPL0 NULL, 0, NULL, 0, 0, 0, 0 }
+};
+size_t extcmdtab_nitems = nitems(cmdtab);
+
+/* satisify the linker */
+int
+findprog(char *prog, char *path, char *filename, size_t filename_size)
+{
+ return 0;
+}
+
+/* satisify the linker */
+struct cmd *
+get_cmdtable(void)
+{
+ return cmdtab;
+}
+
Command *
getcmd(char *name)
{
blob - 715e9630c77e4973a5922efc12dba14edc052442
blob + 7fccb8d5190cff6eab599c628ef2f93fd8662758
--- commands.c
+++ commands.c
{ "su", enablehelp, CMPL(ta) (char **)enabletab, sizeof(Menu), enable, 0, 0, 0, 0 },
{ 0, 0, CMPL0 0, 0, 0, 0, 0, 0, 0 }
};
+
+/*
+ * These commands require externals tools from packages and only appear in
+ * completion lists if the corresponding package is installed.
+ */
+static const char \
+ mtrhelp[] = "network diagnostic tool, similar to ping and traceroute";
+
+struct ghs mtrtab[] = {
+ { "<cr>", "Type Enter to run command", CMPL0 NULL, 0 },
+ { "<IPv4-address>", "IPv4 address parameter", CMPL0 NULL, 0 },
+ { "<IPv6-address>", "IPv6 address parameter", CMPL0 NULL, 0 },
+ { "<hostname>", "hostname parameter", CMPL0 NULL, 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+static int
+extcmd(int argc, char **argv)
+{
+ char prog[PATH_MAX];
+
+ if (!findprog(argv[0], getenv("PATH"), prog, sizeof(prog))) {
+ printf("%% command not found: %s\n", argv[0]);
+ return 1;
+ }
+
+ cmdargs(prog, argv);
+}
+
+Command extcmdtab[] = {
+ { "mtr", mtrhelp, CMPL(h) (char **)mtrtab, sizeof(struct ghs), extcmd, 0, 0, 0, 0 },
+ { NULL, NULL, CMPL0 NULL, 0, NULL, 0, 0, 0, 0 }
+};
+size_t extcmdtab_nitems = nitems(extcmdtab);
+
+static size_t
+count_extcmds(void)
+{
+ struct cmd *c;
+ int i;
+ size_t count = 0;
+ char prog[PATH_MAX];
+
+ for (i = 0; i < extcmdtab_nitems - 1; i++) {
+ c = &extcmdtab[i];
+ if (findprog(c->name, getenv("PATH"), prog, sizeof(prog)))
+ count++;
+ }
+
+ return count;
+}
+
+/* Return a command table with available external commands merged in. */
+struct cmd *
+get_cmdtable(void)
+{
+ static struct cmd *table;
+ static size_t cmd_count_cur;
+ size_t extcmd_count = count_extcmds();
+ size_t total_cmd_count = cmdtab_nitems - 1 + extcmd_count;
+ int i, j;
+
+ if (table && cmd_count_cur == total_cmd_count)
+ return table; /* cached table is still valid */
+
+ table = reallocarray(table, total_cmd_count + 1, sizeof(*table));
+ if (table == NULL) {
+ printf("%% reallocarray: %s", strerror(errno));
+ return cmdtab; /* fall back on not using external commands */
+ }
+ cmd_count_cur = total_cmd_count;
+
+ /* Copy all standard commands into table, excluding sentinel. */
+ for (i = 0; i < cmdtab_nitems - 1; i++) {
+ struct cmd *c = &cmdtab[i];
+ table[i] = *c;
+ }
+
+ /* Add external commands. */
+ for (i = 0, j = 0; i < extcmdtab_nitems - 1 && j < extcmd_count; i++) {
+ struct cmd *c = &extcmdtab[i];
+ char prog[PATH_MAX];
+ if (findprog(c->name, getenv("PATH"), prog, sizeof(prog))) {
+ table[cmdtab_nitems - 1 + j] = *c;
+ j++;
+ }
+ }
+
+ /* Add sentinel. */
+ memset(&table[total_cmd_count], 0, sizeof(*table));
+
+ return table;
+}
+
+struct pkgname {
+ const char *progname;
+ const char *pkgname;
+} pkgnames[] = {
+ { "mtr", "mtr" },
+ { NULL, NULL }
+};
+
+static const char *
+findpkgname(const char *progname)
+{
+ struct pkgname *p = &pkgnames[0];
+ while (p->progname) {
+ if (strcmp(progname, p->progname) == 0)
+ return p->pkgname;
+ p++;
+ }
+
+ return NULL;
+}
+
Command *
getcmd(char *name)
{
Command *cm;
+ const char *pkgname;
- if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
+ cm = (Command *)genget(name, (char **)cmdtab, sizeof(*cm));
+ if (cm)
return cm;
- return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
+
+ cm = (Command *)genget(name, (char **)cmdtab2, sizeof(*cm));
+ if (cm)
+ return cm;
+
+ /* extcmdtab should always be checked last */
+ cm = (Command *)genget(name, (char **)extcmdtab, sizeof(*cm));
+ if (cm) {
+ char prog[PATH_MAX];
+
+ if (findprog(cm->name, getenv("PATH"), prog, sizeof(prog)))
+ return cm;
+
+ pkgname = findpkgname(cm->name);
+ printf("%% external command %s not found%s%s\n", cm->name,
+ pkgname ? "; install the package with: pkg_add " : "",
+ pkgname ? pkgname : "");
+
+ }
+
+ return NULL;
}
void
blob - 0131d0c2dc2b29c0da7575923f5f205a8868bf19
blob + 36506a8866715dff35945fb82608807533b73dc3
--- complete.c
+++ complete.c
unsigned char
complt_c(EditLine *el, int ch)
{
- return(complete(el, (char **)cmdtab, sizeof(struct cmd)));
+ struct cmd *table = get_cmdtable();
+ return complete(el, (char **)table, sizeof(struct cmd));
}
unsigned char
blob - 3eed39cfe7a6df63939115a4588ca1b1a515f480
blob + 9333644c81b3fde83a680a6284c081f645b09313
--- externs.h
+++ externs.h
void command(void);
int argvtostring(int, char **, char *, int);
int cmdrc(char rcname[FILENAME_MAX]);
+struct cmd *get_cmdtable(void);
/* prompt.c */
char *iprompt(void);
extern struct intlist *whichlist;
extern size_t Intlist_nitems;
extern size_t Bridgelist_nitems;
+extern Command extcmdtab[];
+extern size_t extcmdtab_nitems;
/* ieee80211.c */
#define NWID 0
int (*cb)(void *, size_t, void *, size_t, void *),
void *cb_arg);
int hashtable_num_entries(struct hashtable *);
+
+/* findprog.c */
+int findprog(char *, char *, char *, size_t);
+
+/* extcommands.c */
+int cmdmtr(int argc, char **argv);
blob - /dev/null
blob + 67c4bb0e82f07fcb5781a38e5c14659f5aeb3732 (mode 644)
--- /dev/null
+++ findprog.c
+/* $OpenBSD: which.c,v 1.27 2019/01/25 00:19:27 millert Exp $ */
+
+/*
+ * Copyright (c) 1997 Todd C. Miller <millert@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/stat.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "externs.h"
+
+char *default_path = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin:"
+ "/usr/local/bin:/usr/local/sbin:/usr/games";
+
+int
+findprog(char *prog, char *path, char *filename, size_t filename_size)
+{
+ char *p, *mypath;
+ int len, rval = 0;
+ struct stat sbuf;
+ char *pathcpy;
+
+ if (filename_size < PATH_MAX) {
+ printf("%% internal error: findprog buffer too small\n");
+ return (0);
+ }
+
+ /* Special case if prog contains '/' */
+ if (strchr(prog, '/')) {
+ if ((stat(prog, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
+ access(prog, X_OK) == 0) {
+ if (strlcpy(filename, prog, filename_size) >=
+ filename_size) {
+ printf("%% program path too long: %s\n",
+ filename);
+ return (0);
+ }
+ return (1);
+ } else {
+ return (0);
+ }
+ }
+
+ mypath = strdup(path ? path : default_path);
+ if (mypath == NULL) {
+ printf("%% strdup: %s", strerror(errno));
+ return (0);
+ }
+ pathcpy = mypath;
+
+ while ((p = strsep(&pathcpy, ":")) != NULL) {
+ if (*p == '\0')
+ p = ".";
+
+ len = strlen(p);
+ while (len > 0 && p[len-1] == '/')
+ p[--len] = '\0'; /* strip trailing '/' */
+
+ len = snprintf(filename, filename_size, "%s/%s", p, prog);
+ if (len < 0) {
+ printf("%% snprintf: %s\n", strerror(errno));
+ break;
+ }
+ if (len >= filename_size) {
+ printf("%% program path too long: %s\n", filename);
+ break;
+ }
+ if ((stat(filename, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
+ access(filename, X_OK) == 0) {
+ rval = 1;
+ break;
+ }
+ }
+ free(mypath);
+
+ return (rval);
+}
blob - 9564ad11cfdf44c8f81f31ff2f0d694bd6248954
blob + c3eb197920e31efc9b9328a7b69a3702b0401c07
--- helpcommands.c
+++ helpcommands.c
int
help(int argc, char **argv)
{
- Command *c;
+ Command *c, *table = get_cmdtable();
if (argc == 1) {
u_int z = 0;
printf("%% Commands may be abbreviated.\n");
printf("%% Commands are:\n\n");
- for (c = cmdtab; c->name; c++)
+ for (c = table; c->name; c++)
if (((c->needpriv && priv) || !c->needpriv)
&& strlen(c->name) > z)
z = strlen(c->name);
- for (c = cmdtab; c->name; c++) {
+ for (c = table; c->name; c++) {
if (c->help &&
((c->needpriv && priv) || !c->needpriv) &&
((c->needconfig && config_mode) || !c->needconfig))