13b2bd0f6Slogwang
23b2bd0f6Slogwang /*
33b2bd0f6Slogwang * main.c
43b2bd0f6Slogwang *
53b2bd0f6Slogwang * Copyright (c) 1996-1999 Whistle Communications, Inc.
63b2bd0f6Slogwang * All rights reserved.
73b2bd0f6Slogwang *
83b2bd0f6Slogwang * Subject to the following obligations and disclaimer of warranty, use and
93b2bd0f6Slogwang * redistribution of this software, in source or object code forms, with or
103b2bd0f6Slogwang * without modifications are expressly permitted by Whistle Communications;
113b2bd0f6Slogwang * provided, however, that:
123b2bd0f6Slogwang * 1. Any and all reproductions of the source or object code must include the
133b2bd0f6Slogwang * copyright notice above and the following disclaimer of warranties; and
143b2bd0f6Slogwang * 2. No rights are granted, in any manner or form, to use Whistle
153b2bd0f6Slogwang * Communications, Inc. trademarks, including the mark "WHISTLE
163b2bd0f6Slogwang * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
173b2bd0f6Slogwang * such appears in the above copyright notice or in the software.
183b2bd0f6Slogwang *
193b2bd0f6Slogwang * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
203b2bd0f6Slogwang * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
213b2bd0f6Slogwang * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
223b2bd0f6Slogwang * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
233b2bd0f6Slogwang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
243b2bd0f6Slogwang * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
253b2bd0f6Slogwang * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
263b2bd0f6Slogwang * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
273b2bd0f6Slogwang * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
283b2bd0f6Slogwang * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
293b2bd0f6Slogwang * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
303b2bd0f6Slogwang * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
313b2bd0f6Slogwang * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
323b2bd0f6Slogwang * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
333b2bd0f6Slogwang * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
343b2bd0f6Slogwang * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
353b2bd0f6Slogwang * OF SUCH DAMAGE.
363b2bd0f6Slogwang *
373b2bd0f6Slogwang * $Whistle: main.c,v 1.12 1999/11/29 19:17:46 archie Exp $
383b2bd0f6Slogwang */
393b2bd0f6Slogwang
403b2bd0f6Slogwang #include <sys/cdefs.h>
413b2bd0f6Slogwang __FBSDID("$FreeBSD$");
423b2bd0f6Slogwang
433b2bd0f6Slogwang #include <sys/param.h>
443b2bd0f6Slogwang #include <sys/socket.h>
453b2bd0f6Slogwang #include <sys/select.h>
463b2bd0f6Slogwang
473b2bd0f6Slogwang #include <ctype.h>
483b2bd0f6Slogwang #include <err.h>
493b2bd0f6Slogwang #include <errno.h>
503b2bd0f6Slogwang #include <limits.h>
513b2bd0f6Slogwang #include <stdio.h>
523b2bd0f6Slogwang #include <stdlib.h>
533b2bd0f6Slogwang #include <string.h>
543b2bd0f6Slogwang #include <sysexits.h>
553b2bd0f6Slogwang #include <unistd.h>
563b2bd0f6Slogwang #ifdef EDITLINE
573b2bd0f6Slogwang #include <signal.h>
583b2bd0f6Slogwang #include <histedit.h>
593b2bd0f6Slogwang #include <pthread.h>
603b2bd0f6Slogwang #endif
613b2bd0f6Slogwang
623b2bd0f6Slogwang #include <netgraph.h>
633b2bd0f6Slogwang
643b2bd0f6Slogwang #include "ngctl.h"
653b2bd0f6Slogwang
66*d4a07e70Sfengbojiang #ifdef FSTACK
67*d4a07e70Sfengbojiang #include "ff_ipc.h"
68*d4a07e70Sfengbojiang #endif
69*d4a07e70Sfengbojiang
703b2bd0f6Slogwang #define PROMPT "+ "
713b2bd0f6Slogwang #define MAX_ARGS 512
723b2bd0f6Slogwang #define WHITESPACE " \t\r\n\v\f"
733b2bd0f6Slogwang #define DUMP_BYTES_PER_LINE 16
743b2bd0f6Slogwang
753b2bd0f6Slogwang /* Internal functions */
763b2bd0f6Slogwang static int ReadFile(FILE *fp);
77*d4a07e70Sfengbojiang #ifndef FSTACK
783b2bd0f6Slogwang static void ReadSockets(fd_set *);
79*d4a07e70Sfengbojiang #endif
803b2bd0f6Slogwang static int DoParseCommand(const char *line);
813b2bd0f6Slogwang static int DoCommand(int ac, char **av);
823b2bd0f6Slogwang static int DoInteractive(void);
833b2bd0f6Slogwang static const struct ngcmd *FindCommand(const char *string);
843b2bd0f6Slogwang static int MatchCommand(const struct ngcmd *cmd, const char *s);
853b2bd0f6Slogwang static void Usage(const char *msg);
863b2bd0f6Slogwang static int ReadCmd(int ac, char **av);
873b2bd0f6Slogwang static int HelpCmd(int ac, char **av);
883b2bd0f6Slogwang static int QuitCmd(int ac, char **av);
893b2bd0f6Slogwang #ifdef EDITLINE
90*d4a07e70Sfengbojiang #ifndef FSTACK
913b2bd0f6Slogwang static volatile sig_atomic_t unblock;
923b2bd0f6Slogwang static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
933b2bd0f6Slogwang static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
943b2bd0f6Slogwang #endif
95*d4a07e70Sfengbojiang #endif
963b2bd0f6Slogwang
973b2bd0f6Slogwang /* List of commands */
983b2bd0f6Slogwang static const struct ngcmd *const cmds[] = {
993b2bd0f6Slogwang &config_cmd,
1003b2bd0f6Slogwang &connect_cmd,
1013b2bd0f6Slogwang &debug_cmd,
1023b2bd0f6Slogwang &dot_cmd,
1033b2bd0f6Slogwang &help_cmd,
1043b2bd0f6Slogwang &list_cmd,
1053b2bd0f6Slogwang &mkpeer_cmd,
1063b2bd0f6Slogwang &msg_cmd,
1073b2bd0f6Slogwang &name_cmd,
1083b2bd0f6Slogwang &read_cmd,
1093b2bd0f6Slogwang &rmhook_cmd,
1103b2bd0f6Slogwang &show_cmd,
1113b2bd0f6Slogwang &shutdown_cmd,
1123b2bd0f6Slogwang &status_cmd,
1133b2bd0f6Slogwang &types_cmd,
1143b2bd0f6Slogwang &write_cmd,
1153b2bd0f6Slogwang &quit_cmd,
1163b2bd0f6Slogwang NULL
1173b2bd0f6Slogwang };
1183b2bd0f6Slogwang
1193b2bd0f6Slogwang /* Commands defined in this file */
1203b2bd0f6Slogwang const struct ngcmd read_cmd = {
1213b2bd0f6Slogwang ReadCmd,
1223b2bd0f6Slogwang "read <filename>",
1233b2bd0f6Slogwang "Read and execute commands from a file",
1243b2bd0f6Slogwang NULL,
1253b2bd0f6Slogwang { "source", "." }
1263b2bd0f6Slogwang };
1273b2bd0f6Slogwang const struct ngcmd help_cmd = {
1283b2bd0f6Slogwang HelpCmd,
1293b2bd0f6Slogwang "help [command]",
1303b2bd0f6Slogwang "Show command summary or get more help on a specific command",
1313b2bd0f6Slogwang NULL,
1323b2bd0f6Slogwang { "?" }
1333b2bd0f6Slogwang };
1343b2bd0f6Slogwang const struct ngcmd quit_cmd = {
1353b2bd0f6Slogwang QuitCmd,
1363b2bd0f6Slogwang "quit",
1373b2bd0f6Slogwang "Exit program",
1383b2bd0f6Slogwang NULL,
1393b2bd0f6Slogwang { "exit" }
1403b2bd0f6Slogwang };
1413b2bd0f6Slogwang
1423b2bd0f6Slogwang /* Our control and data sockets */
143*d4a07e70Sfengbojiang #ifndef FSTACK
1443b2bd0f6Slogwang int csock, dsock;
145*d4a07e70Sfengbojiang #else
146*d4a07e70Sfengbojiang int csock = -1, dsock = -1;
147*d4a07e70Sfengbojiang
148*d4a07e70Sfengbojiang void
close_ng_socks()149*d4a07e70Sfengbojiang __attribute__((destructor)) close_ng_socks()
150*d4a07e70Sfengbojiang {
151*d4a07e70Sfengbojiang if (csock >= 0) {
152*d4a07e70Sfengbojiang ng_close(csock);
153*d4a07e70Sfengbojiang }
154*d4a07e70Sfengbojiang
155*d4a07e70Sfengbojiang if (dsock >= 0) {
156*d4a07e70Sfengbojiang ng_close(dsock);
157*d4a07e70Sfengbojiang }
158*d4a07e70Sfengbojiang }
159*d4a07e70Sfengbojiang #endif
1603b2bd0f6Slogwang
1613b2bd0f6Slogwang /*
1623b2bd0f6Slogwang * main()
1633b2bd0f6Slogwang */
1643b2bd0f6Slogwang int
main(int ac,char * av[])1653b2bd0f6Slogwang main(int ac, char *av[])
1663b2bd0f6Slogwang {
1673b2bd0f6Slogwang char name[NG_NODESIZ];
1683b2bd0f6Slogwang int interactive = isatty(0) && isatty(1);
1693b2bd0f6Slogwang FILE *fp = NULL;
1703b2bd0f6Slogwang int ch, rtn = 0;
1713b2bd0f6Slogwang
1723b2bd0f6Slogwang /* Set default node name */
1733b2bd0f6Slogwang snprintf(name, sizeof(name), "ngctl%d", getpid());
1743b2bd0f6Slogwang
1753b2bd0f6Slogwang /* Parse command line */
176*d4a07e70Sfengbojiang #ifndef FSTACK
1773b2bd0f6Slogwang while ((ch = getopt(ac, av, "df:n:")) != -1) {
178*d4a07e70Sfengbojiang #else
179*d4a07e70Sfengbojiang ff_ipc_init();
180*d4a07e70Sfengbojiang while ((ch = getopt(ac, av, "df:n:p:")) != -1) {
181*d4a07e70Sfengbojiang #endif
1823b2bd0f6Slogwang switch (ch) {
1833b2bd0f6Slogwang case 'd':
1843b2bd0f6Slogwang NgSetDebug(NgSetDebug(-1) + 1);
1853b2bd0f6Slogwang break;
1863b2bd0f6Slogwang case 'f':
1873b2bd0f6Slogwang if (strcmp(optarg, "-") == 0)
1883b2bd0f6Slogwang fp = stdin;
1893b2bd0f6Slogwang else if ((fp = fopen(optarg, "r")) == NULL)
1903b2bd0f6Slogwang err(EX_NOINPUT, "%s", optarg);
1913b2bd0f6Slogwang break;
1923b2bd0f6Slogwang case 'n':
1933b2bd0f6Slogwang snprintf(name, sizeof(name), "%s", optarg);
1943b2bd0f6Slogwang break;
195*d4a07e70Sfengbojiang #ifdef FSTACK
196*d4a07e70Sfengbojiang case 'p':
197*d4a07e70Sfengbojiang ff_set_proc_id(atoi(optarg));
198*d4a07e70Sfengbojiang break;
199*d4a07e70Sfengbojiang #endif
2003b2bd0f6Slogwang case '?':
2013b2bd0f6Slogwang default:
2023b2bd0f6Slogwang Usage((char *)NULL);
2033b2bd0f6Slogwang break;
2043b2bd0f6Slogwang }
2053b2bd0f6Slogwang }
2063b2bd0f6Slogwang ac -= optind;
2073b2bd0f6Slogwang av += optind;
2083b2bd0f6Slogwang
2093b2bd0f6Slogwang /* Create a new socket node */
2103b2bd0f6Slogwang if (NgMkSockNode(name, &csock, &dsock) < 0)
2113b2bd0f6Slogwang err(EX_OSERR, "can't create node");
2123b2bd0f6Slogwang
2133b2bd0f6Slogwang /* Do commands as requested */
2143b2bd0f6Slogwang if (ac == 0) {
2153b2bd0f6Slogwang if (fp != NULL) {
2163b2bd0f6Slogwang rtn = ReadFile(fp);
2173b2bd0f6Slogwang } else if (interactive) {
2183b2bd0f6Slogwang rtn = DoInteractive();
2193b2bd0f6Slogwang } else
2203b2bd0f6Slogwang Usage("no command specified");
2213b2bd0f6Slogwang } else {
2223b2bd0f6Slogwang rtn = DoCommand(ac, av);
2233b2bd0f6Slogwang }
2243b2bd0f6Slogwang
2253b2bd0f6Slogwang /* Convert command return code into system exit code */
2263b2bd0f6Slogwang switch (rtn) {
2273b2bd0f6Slogwang case CMDRTN_OK:
2283b2bd0f6Slogwang case CMDRTN_QUIT:
2293b2bd0f6Slogwang rtn = 0;
2303b2bd0f6Slogwang break;
2313b2bd0f6Slogwang case CMDRTN_USAGE:
2323b2bd0f6Slogwang rtn = EX_USAGE;
2333b2bd0f6Slogwang break;
2343b2bd0f6Slogwang case CMDRTN_ERROR:
2353b2bd0f6Slogwang rtn = EX_OSERR;
2363b2bd0f6Slogwang break;
2373b2bd0f6Slogwang }
238*d4a07e70Sfengbojiang #ifdef FSTACK
239*d4a07e70Sfengbojiang ff_ipc_exit();
240*d4a07e70Sfengbojiang #endif
2413b2bd0f6Slogwang return (rtn);
2423b2bd0f6Slogwang }
2433b2bd0f6Slogwang
2443b2bd0f6Slogwang /*
2453b2bd0f6Slogwang * Process commands from a file
2463b2bd0f6Slogwang */
2473b2bd0f6Slogwang static int
2483b2bd0f6Slogwang ReadFile(FILE *fp)
2493b2bd0f6Slogwang {
2503b2bd0f6Slogwang char line[LINE_MAX];
2513b2bd0f6Slogwang int num, rtn;
2523b2bd0f6Slogwang
2533b2bd0f6Slogwang for (num = 1; fgets(line, sizeof(line), fp) != NULL; num++) {
2543b2bd0f6Slogwang if (*line == '#')
2553b2bd0f6Slogwang continue;
2563b2bd0f6Slogwang if ((rtn = DoParseCommand(line)) != 0) {
2573b2bd0f6Slogwang warnx("line %d: error in file", num);
2583b2bd0f6Slogwang return (rtn);
2593b2bd0f6Slogwang }
2603b2bd0f6Slogwang }
2613b2bd0f6Slogwang return (CMDRTN_OK);
2623b2bd0f6Slogwang }
2633b2bd0f6Slogwang
2643b2bd0f6Slogwang #ifdef EDITLINE
265*d4a07e70Sfengbojiang #ifndef FSTACK
2663b2bd0f6Slogwang /* Signal handler for Monitor() thread. */
2673b2bd0f6Slogwang static void
2683b2bd0f6Slogwang Unblock(int signal __unused)
2693b2bd0f6Slogwang {
2703b2bd0f6Slogwang
2713b2bd0f6Slogwang unblock = 1;
2723b2bd0f6Slogwang }
2733b2bd0f6Slogwang
2743b2bd0f6Slogwang /*
2753b2bd0f6Slogwang * Thread that monitors csock and dsock while main thread
2763b2bd0f6Slogwang * can be blocked in el_gets().
2773b2bd0f6Slogwang */
2783b2bd0f6Slogwang static void *
2793b2bd0f6Slogwang Monitor(void *v __unused)
2803b2bd0f6Slogwang {
2813b2bd0f6Slogwang struct sigaction act;
2823b2bd0f6Slogwang const int maxfd = MAX(csock, dsock) + 1;
2833b2bd0f6Slogwang
2843b2bd0f6Slogwang act.sa_handler = Unblock;
2853b2bd0f6Slogwang sigemptyset(&act.sa_mask);
2863b2bd0f6Slogwang act.sa_flags = 0;
2873b2bd0f6Slogwang sigaction(SIGUSR1, &act, NULL);
2883b2bd0f6Slogwang
2893b2bd0f6Slogwang pthread_mutex_lock(&mutex);
2903b2bd0f6Slogwang for (;;) {
2913b2bd0f6Slogwang fd_set rfds;
2923b2bd0f6Slogwang
2933b2bd0f6Slogwang /* See if any data or control messages are arriving. */
2943b2bd0f6Slogwang FD_ZERO(&rfds);
2953b2bd0f6Slogwang FD_SET(csock, &rfds);
2963b2bd0f6Slogwang FD_SET(dsock, &rfds);
2973b2bd0f6Slogwang unblock = 0;
2983b2bd0f6Slogwang if (select(maxfd, &rfds, NULL, NULL, NULL) <= 0) {
2993b2bd0f6Slogwang if (errno == EINTR) {
3003b2bd0f6Slogwang if (unblock == 1)
3013b2bd0f6Slogwang pthread_cond_wait(&cond, &mutex);
3023b2bd0f6Slogwang continue;
3033b2bd0f6Slogwang }
3043b2bd0f6Slogwang err(EX_OSERR, "select");
3053b2bd0f6Slogwang }
3063b2bd0f6Slogwang ReadSockets(&rfds);
3073b2bd0f6Slogwang }
3083b2bd0f6Slogwang
3093b2bd0f6Slogwang return (NULL);
3103b2bd0f6Slogwang }
311*d4a07e70Sfengbojiang #endif
3123b2bd0f6Slogwang
3133b2bd0f6Slogwang static char *
3143b2bd0f6Slogwang Prompt(EditLine *el __unused)
3153b2bd0f6Slogwang {
3163b2bd0f6Slogwang
3173b2bd0f6Slogwang return (PROMPT);
3183b2bd0f6Slogwang }
3193b2bd0f6Slogwang
3203b2bd0f6Slogwang /*
3213b2bd0f6Slogwang * Here we start a thread, that will monitor the netgraph
3223b2bd0f6Slogwang * sockets and catch any unexpected messages or data on them,
3233b2bd0f6Slogwang * that can arrive while user edits his/her commands.
3243b2bd0f6Slogwang *
3253b2bd0f6Slogwang * Whenever we expect data on netgraph sockets, we send signal
3263b2bd0f6Slogwang * to monitoring thread. The signal forces it to exit select()
3273b2bd0f6Slogwang * system call and sleep on condvar until we wake it. While
3283b2bd0f6Slogwang * monitoring thread sleeps, we can do our work with netgraph
3293b2bd0f6Slogwang * sockets.
3303b2bd0f6Slogwang */
3313b2bd0f6Slogwang static int
3323b2bd0f6Slogwang DoInteractive(void)
3333b2bd0f6Slogwang {
334*d4a07e70Sfengbojiang #ifndef FSTACK
3353b2bd0f6Slogwang pthread_t monitor;
336*d4a07e70Sfengbojiang #endif
3373b2bd0f6Slogwang EditLine *el;
3383b2bd0f6Slogwang History *hist;
3393b2bd0f6Slogwang HistEvent hev = { 0, "" };
3403b2bd0f6Slogwang
3413b2bd0f6Slogwang (*help_cmd.func)(0, NULL);
342*d4a07e70Sfengbojiang #ifndef FSTACK
3433b2bd0f6Slogwang pthread_create(&monitor, NULL, Monitor, NULL);
344*d4a07e70Sfengbojiang #endif
3453b2bd0f6Slogwang el = el_init(getprogname(), stdin, stdout, stderr);
3463b2bd0f6Slogwang if (el == NULL)
3473b2bd0f6Slogwang return (CMDRTN_ERROR);
3483b2bd0f6Slogwang el_set(el, EL_PROMPT, Prompt);
3493b2bd0f6Slogwang el_set(el, EL_SIGNAL, 1);
3503b2bd0f6Slogwang el_set(el, EL_EDITOR, "emacs");
3513b2bd0f6Slogwang hist = history_init();
3523b2bd0f6Slogwang if (hist == NULL)
3533b2bd0f6Slogwang return (CMDRTN_ERROR);
3543b2bd0f6Slogwang history(hist, &hev, H_SETSIZE, 100);
3553b2bd0f6Slogwang history(hist, &hev, H_SETUNIQUE, 1);
3563b2bd0f6Slogwang el_set(el, EL_HIST, history, (const char *)hist);
3573b2bd0f6Slogwang el_source(el, NULL);
3583b2bd0f6Slogwang
3593b2bd0f6Slogwang for (;;) {
3603b2bd0f6Slogwang const char *buf;
3613b2bd0f6Slogwang int count;
3623b2bd0f6Slogwang
3633b2bd0f6Slogwang if ((buf = el_gets(el, &count)) == NULL) {
3643b2bd0f6Slogwang printf("\n");
3653b2bd0f6Slogwang break;
3663b2bd0f6Slogwang }
3673b2bd0f6Slogwang history(hist, &hev, H_ENTER, buf);
368*d4a07e70Sfengbojiang #ifndef FSTACK
3693b2bd0f6Slogwang pthread_kill(monitor, SIGUSR1);
3703b2bd0f6Slogwang pthread_mutex_lock(&mutex);
371*d4a07e70Sfengbojiang #endif
3723b2bd0f6Slogwang if (DoParseCommand(buf) == CMDRTN_QUIT) {
373*d4a07e70Sfengbojiang #ifndef FSTACK
3743b2bd0f6Slogwang pthread_mutex_unlock(&mutex);
375*d4a07e70Sfengbojiang #endif
3763b2bd0f6Slogwang break;
3773b2bd0f6Slogwang }
378*d4a07e70Sfengbojiang #ifndef FSTACK
3793b2bd0f6Slogwang pthread_cond_signal(&cond);
3803b2bd0f6Slogwang pthread_mutex_unlock(&mutex);
381*d4a07e70Sfengbojiang #endif
3823b2bd0f6Slogwang }
3833b2bd0f6Slogwang
3843b2bd0f6Slogwang history_end(hist);
3853b2bd0f6Slogwang el_end(el);
386*d4a07e70Sfengbojiang #ifndef FSTACK
3873b2bd0f6Slogwang pthread_cancel(monitor);
388*d4a07e70Sfengbojiang #endif
3893b2bd0f6Slogwang
3903b2bd0f6Slogwang return (CMDRTN_QUIT);
3913b2bd0f6Slogwang }
3923b2bd0f6Slogwang
3933b2bd0f6Slogwang #else /* !EDITLINE */
3943b2bd0f6Slogwang
3953b2bd0f6Slogwang /*
3963b2bd0f6Slogwang * Interactive mode w/o libedit functionality.
3973b2bd0f6Slogwang */
3983b2bd0f6Slogwang static int
3993b2bd0f6Slogwang DoInteractive(void)
4003b2bd0f6Slogwang {
4013b2bd0f6Slogwang const int maxfd = MAX(csock, dsock) + 1;
4023b2bd0f6Slogwang
4033b2bd0f6Slogwang (*help_cmd.func)(0, NULL);
4043b2bd0f6Slogwang while (1) {
4053b2bd0f6Slogwang struct timeval tv;
4063b2bd0f6Slogwang fd_set rfds;
4073b2bd0f6Slogwang
4083b2bd0f6Slogwang /* See if any data or control messages are arriving */
4093b2bd0f6Slogwang FD_ZERO(&rfds);
410*d4a07e70Sfengbojiang #ifndef FSTACK
4113b2bd0f6Slogwang FD_SET(csock, &rfds);
4123b2bd0f6Slogwang FD_SET(dsock, &rfds);
413*d4a07e70Sfengbojiang #endif
4143b2bd0f6Slogwang memset(&tv, 0, sizeof(tv));
4153b2bd0f6Slogwang if (select(maxfd, &rfds, NULL, NULL, &tv) <= 0) {
4163b2bd0f6Slogwang
4173b2bd0f6Slogwang /* Issue prompt and wait for anything to happen */
4183b2bd0f6Slogwang printf("%s", PROMPT);
4193b2bd0f6Slogwang fflush(stdout);
4203b2bd0f6Slogwang FD_ZERO(&rfds);
4213b2bd0f6Slogwang FD_SET(0, &rfds);
422*d4a07e70Sfengbojiang #ifndef FSTACK
4233b2bd0f6Slogwang FD_SET(csock, &rfds);
4243b2bd0f6Slogwang FD_SET(dsock, &rfds);
425*d4a07e70Sfengbojiang #endif
4263b2bd0f6Slogwang if (select(maxfd, &rfds, NULL, NULL, NULL) < 0)
4273b2bd0f6Slogwang err(EX_OSERR, "select");
4283b2bd0f6Slogwang
4293b2bd0f6Slogwang /* If not user input, print a newline first */
4303b2bd0f6Slogwang if (!FD_ISSET(0, &rfds))
4313b2bd0f6Slogwang printf("\n");
4323b2bd0f6Slogwang }
4333b2bd0f6Slogwang
434*d4a07e70Sfengbojiang #ifndef FSTACK
4353b2bd0f6Slogwang ReadSockets(&rfds);
436*d4a07e70Sfengbojiang #endif
4373b2bd0f6Slogwang
4383b2bd0f6Slogwang /* Get any user input */
4393b2bd0f6Slogwang if (FD_ISSET(0, &rfds)) {
4403b2bd0f6Slogwang char buf[LINE_MAX];
4413b2bd0f6Slogwang
4423b2bd0f6Slogwang if (fgets(buf, sizeof(buf), stdin) == NULL) {
4433b2bd0f6Slogwang printf("\n");
4443b2bd0f6Slogwang break;
4453b2bd0f6Slogwang }
4463b2bd0f6Slogwang if (DoParseCommand(buf) == CMDRTN_QUIT)
4473b2bd0f6Slogwang break;
4483b2bd0f6Slogwang }
4493b2bd0f6Slogwang }
4503b2bd0f6Slogwang return (CMDRTN_QUIT);
4513b2bd0f6Slogwang }
4523b2bd0f6Slogwang #endif /* !EDITLINE */
4533b2bd0f6Slogwang
454*d4a07e70Sfengbojiang #ifndef FSTACK
4553b2bd0f6Slogwang /*
4563b2bd0f6Slogwang * Read and process data on netgraph control and data sockets.
4573b2bd0f6Slogwang */
4583b2bd0f6Slogwang static void
4593b2bd0f6Slogwang ReadSockets(fd_set *rfds)
4603b2bd0f6Slogwang {
4613b2bd0f6Slogwang /* Display any incoming control message. */
4623b2bd0f6Slogwang if (FD_ISSET(csock, rfds))
4633b2bd0f6Slogwang MsgRead();
4643b2bd0f6Slogwang
4653b2bd0f6Slogwang /* Display any incoming data packet. */
4663b2bd0f6Slogwang if (FD_ISSET(dsock, rfds)) {
4673b2bd0f6Slogwang char hook[NG_HOOKSIZ];
4683b2bd0f6Slogwang u_char *buf;
4693b2bd0f6Slogwang int rl;
4703b2bd0f6Slogwang
4713b2bd0f6Slogwang /* Read packet from socket. */
4723b2bd0f6Slogwang if ((rl = NgAllocRecvData(dsock, &buf, hook)) < 0)
4733b2bd0f6Slogwang err(EX_OSERR, "reading hook \"%s\"", hook);
4743b2bd0f6Slogwang if (rl == 0)
4753b2bd0f6Slogwang errx(EX_OSERR, "EOF from hook \"%s\"?", hook);
4763b2bd0f6Slogwang
4773b2bd0f6Slogwang /* Write packet to stdout. */
4783b2bd0f6Slogwang printf("Rec'd data packet on hook \"%s\":\n", hook);
4793b2bd0f6Slogwang DumpAscii(buf, rl);
4803b2bd0f6Slogwang free(buf);
4813b2bd0f6Slogwang }
4823b2bd0f6Slogwang }
483*d4a07e70Sfengbojiang #endif
4843b2bd0f6Slogwang
4853b2bd0f6Slogwang /*
4863b2bd0f6Slogwang * Parse a command line and execute the command
4873b2bd0f6Slogwang */
4883b2bd0f6Slogwang static int
4893b2bd0f6Slogwang DoParseCommand(const char *line)
4903b2bd0f6Slogwang {
4913b2bd0f6Slogwang char *av[MAX_ARGS];
4923b2bd0f6Slogwang int ac;
4933b2bd0f6Slogwang
4943b2bd0f6Slogwang /* Parse line */
4953b2bd0f6Slogwang for (ac = 0, av[0] = strtok((char *)line, WHITESPACE);
4963b2bd0f6Slogwang ac < MAX_ARGS - 1 && av[ac];
4973b2bd0f6Slogwang av[++ac] = strtok(NULL, WHITESPACE));
4983b2bd0f6Slogwang
4993b2bd0f6Slogwang /* Do command */
5003b2bd0f6Slogwang return (DoCommand(ac, av));
5013b2bd0f6Slogwang }
5023b2bd0f6Slogwang
5033b2bd0f6Slogwang /*
5043b2bd0f6Slogwang * Execute the command
5053b2bd0f6Slogwang */
5063b2bd0f6Slogwang static int
5073b2bd0f6Slogwang DoCommand(int ac, char **av)
5083b2bd0f6Slogwang {
5093b2bd0f6Slogwang const struct ngcmd *cmd;
5103b2bd0f6Slogwang int rtn;
5113b2bd0f6Slogwang
5123b2bd0f6Slogwang if (ac == 0 || *av[0] == 0)
5133b2bd0f6Slogwang return (CMDRTN_OK);
5143b2bd0f6Slogwang if ((cmd = FindCommand(av[0])) == NULL)
5153b2bd0f6Slogwang return (CMDRTN_ERROR);
5163b2bd0f6Slogwang if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE)
5173b2bd0f6Slogwang warnx("usage: %s", cmd->cmd);
5183b2bd0f6Slogwang return (rtn);
5193b2bd0f6Slogwang }
5203b2bd0f6Slogwang
5213b2bd0f6Slogwang /*
5223b2bd0f6Slogwang * Find a command
5233b2bd0f6Slogwang */
5243b2bd0f6Slogwang static const struct ngcmd *
5253b2bd0f6Slogwang FindCommand(const char *string)
5263b2bd0f6Slogwang {
5273b2bd0f6Slogwang int k, found = -1;
5283b2bd0f6Slogwang
5293b2bd0f6Slogwang for (k = 0; cmds[k] != NULL; k++) {
5303b2bd0f6Slogwang if (MatchCommand(cmds[k], string)) {
5313b2bd0f6Slogwang if (found != -1) {
5323b2bd0f6Slogwang warnx("\"%s\": ambiguous command", string);
5333b2bd0f6Slogwang return (NULL);
5343b2bd0f6Slogwang }
5353b2bd0f6Slogwang found = k;
5363b2bd0f6Slogwang }
5373b2bd0f6Slogwang }
5383b2bd0f6Slogwang if (found == -1) {
5393b2bd0f6Slogwang warnx("\"%s\": unknown command", string);
5403b2bd0f6Slogwang return (NULL);
5413b2bd0f6Slogwang }
5423b2bd0f6Slogwang return (cmds[found]);
5433b2bd0f6Slogwang }
5443b2bd0f6Slogwang
5453b2bd0f6Slogwang /*
5463b2bd0f6Slogwang * See if string matches a prefix of "cmd" (or an alias) case insensitively
5473b2bd0f6Slogwang */
5483b2bd0f6Slogwang static int
5493b2bd0f6Slogwang MatchCommand(const struct ngcmd *cmd, const char *s)
5503b2bd0f6Slogwang {
5513b2bd0f6Slogwang int a;
5523b2bd0f6Slogwang
5533b2bd0f6Slogwang /* Try to match command, ignoring the usage stuff */
5543b2bd0f6Slogwang if (strlen(s) <= strcspn(cmd->cmd, WHITESPACE)) {
5553b2bd0f6Slogwang if (strncasecmp(s, cmd->cmd, strlen(s)) == 0)
5563b2bd0f6Slogwang return (1);
5573b2bd0f6Slogwang }
5583b2bd0f6Slogwang
5593b2bd0f6Slogwang /* Try to match aliases */
5603b2bd0f6Slogwang for (a = 0; a < MAX_CMD_ALIAS && cmd->aliases[a] != NULL; a++) {
5613b2bd0f6Slogwang if (strlen(cmd->aliases[a]) >= strlen(s)) {
5623b2bd0f6Slogwang if (strncasecmp(s, cmd->aliases[a], strlen(s)) == 0)
5633b2bd0f6Slogwang return (1);
5643b2bd0f6Slogwang }
5653b2bd0f6Slogwang }
5663b2bd0f6Slogwang
5673b2bd0f6Slogwang /* No match */
5683b2bd0f6Slogwang return (0);
5693b2bd0f6Slogwang }
5703b2bd0f6Slogwang
5713b2bd0f6Slogwang /*
5723b2bd0f6Slogwang * ReadCmd()
5733b2bd0f6Slogwang */
5743b2bd0f6Slogwang static int
5753b2bd0f6Slogwang ReadCmd(int ac, char **av)
5763b2bd0f6Slogwang {
5773b2bd0f6Slogwang FILE *fp;
5783b2bd0f6Slogwang int rtn;
5793b2bd0f6Slogwang
5803b2bd0f6Slogwang /* Open file */
5813b2bd0f6Slogwang switch (ac) {
5823b2bd0f6Slogwang case 2:
5833b2bd0f6Slogwang if ((fp = fopen(av[1], "r")) == NULL) {
5843b2bd0f6Slogwang warn("%s", av[1]);
5853b2bd0f6Slogwang return (CMDRTN_ERROR);
5863b2bd0f6Slogwang }
5873b2bd0f6Slogwang break;
5883b2bd0f6Slogwang default:
5893b2bd0f6Slogwang return (CMDRTN_USAGE);
5903b2bd0f6Slogwang }
5913b2bd0f6Slogwang
5923b2bd0f6Slogwang /* Process it */
5933b2bd0f6Slogwang rtn = ReadFile(fp);
5943b2bd0f6Slogwang fclose(fp);
5953b2bd0f6Slogwang return (rtn);
5963b2bd0f6Slogwang }
5973b2bd0f6Slogwang
5983b2bd0f6Slogwang /*
5993b2bd0f6Slogwang * HelpCmd()
6003b2bd0f6Slogwang */
6013b2bd0f6Slogwang static int
6023b2bd0f6Slogwang HelpCmd(int ac, char **av)
6033b2bd0f6Slogwang {
6043b2bd0f6Slogwang const struct ngcmd *cmd;
6053b2bd0f6Slogwang int k;
6063b2bd0f6Slogwang
6073b2bd0f6Slogwang switch (ac) {
6083b2bd0f6Slogwang case 0:
6093b2bd0f6Slogwang case 1:
6103b2bd0f6Slogwang /* Show all commands */
6113b2bd0f6Slogwang printf("Available commands:\n");
6123b2bd0f6Slogwang for (k = 0; cmds[k] != NULL; k++) {
6133b2bd0f6Slogwang char *s, buf[100];
6143b2bd0f6Slogwang
6153b2bd0f6Slogwang cmd = cmds[k];
6163b2bd0f6Slogwang snprintf(buf, sizeof(buf), "%s", cmd->cmd);
6173b2bd0f6Slogwang for (s = buf; *s != '\0' && !isspace(*s); s++);
6183b2bd0f6Slogwang *s = '\0';
6193b2bd0f6Slogwang printf(" %-10s %s\n", buf, cmd->desc);
6203b2bd0f6Slogwang }
6213b2bd0f6Slogwang return (CMDRTN_OK);
6223b2bd0f6Slogwang default:
6233b2bd0f6Slogwang /* Show help on a specific command */
6243b2bd0f6Slogwang if ((cmd = FindCommand(av[1])) != NULL) {
6253b2bd0f6Slogwang printf("usage: %s\n", cmd->cmd);
6263b2bd0f6Slogwang if (cmd->aliases[0] != NULL) {
6273b2bd0f6Slogwang int a = 0;
6283b2bd0f6Slogwang
6293b2bd0f6Slogwang printf("Aliases: ");
6303b2bd0f6Slogwang while (1) {
6313b2bd0f6Slogwang printf("%s", cmd->aliases[a++]);
6323b2bd0f6Slogwang if (a == MAX_CMD_ALIAS
6333b2bd0f6Slogwang || cmd->aliases[a] == NULL) {
6343b2bd0f6Slogwang printf("\n");
6353b2bd0f6Slogwang break;
6363b2bd0f6Slogwang }
6373b2bd0f6Slogwang printf(", ");
6383b2bd0f6Slogwang }
6393b2bd0f6Slogwang }
6403b2bd0f6Slogwang printf("Summary: %s\n", cmd->desc);
6413b2bd0f6Slogwang if (cmd->help != NULL) {
6423b2bd0f6Slogwang const char *s;
6433b2bd0f6Slogwang char buf[65];
6443b2bd0f6Slogwang int tot, len, done;
6453b2bd0f6Slogwang
6463b2bd0f6Slogwang printf("Description:\n");
6473b2bd0f6Slogwang for (s = cmd->help; *s != '\0'; s += len) {
6483b2bd0f6Slogwang while (isspace(*s))
6493b2bd0f6Slogwang s++;
6503b2bd0f6Slogwang tot = snprintf(buf,
6513b2bd0f6Slogwang sizeof(buf), "%s", s);
6523b2bd0f6Slogwang len = strlen(buf);
6533b2bd0f6Slogwang done = len == tot;
6543b2bd0f6Slogwang if (!done) {
6553b2bd0f6Slogwang while (len > 0
6563b2bd0f6Slogwang && !isspace(buf[len-1]))
6573b2bd0f6Slogwang buf[--len] = '\0';
6583b2bd0f6Slogwang }
6593b2bd0f6Slogwang printf(" %s\n", buf);
6603b2bd0f6Slogwang }
6613b2bd0f6Slogwang }
6623b2bd0f6Slogwang }
6633b2bd0f6Slogwang }
6643b2bd0f6Slogwang return (CMDRTN_OK);
6653b2bd0f6Slogwang }
6663b2bd0f6Slogwang
6673b2bd0f6Slogwang /*
6683b2bd0f6Slogwang * QuitCmd()
6693b2bd0f6Slogwang */
6703b2bd0f6Slogwang static int
6713b2bd0f6Slogwang QuitCmd(int ac __unused, char **av __unused)
6723b2bd0f6Slogwang {
6733b2bd0f6Slogwang return (CMDRTN_QUIT);
6743b2bd0f6Slogwang }
6753b2bd0f6Slogwang
6763b2bd0f6Slogwang /*
6773b2bd0f6Slogwang * Dump data in hex and ASCII form
6783b2bd0f6Slogwang */
6793b2bd0f6Slogwang void
6803b2bd0f6Slogwang DumpAscii(const u_char *buf, int len)
6813b2bd0f6Slogwang {
6823b2bd0f6Slogwang char ch, sbuf[100];
6833b2bd0f6Slogwang int k, count;
6843b2bd0f6Slogwang
6853b2bd0f6Slogwang for (count = 0; count < len; count += DUMP_BYTES_PER_LINE) {
6863b2bd0f6Slogwang snprintf(sbuf, sizeof(sbuf), "%04x: ", count);
6873b2bd0f6Slogwang for (k = 0; k < DUMP_BYTES_PER_LINE; k++) {
6883b2bd0f6Slogwang if (count + k < len) {
6893b2bd0f6Slogwang snprintf(sbuf + strlen(sbuf),
6903b2bd0f6Slogwang sizeof(sbuf) - strlen(sbuf),
6913b2bd0f6Slogwang "%02x ", buf[count + k]);
6923b2bd0f6Slogwang } else {
6933b2bd0f6Slogwang snprintf(sbuf + strlen(sbuf),
6943b2bd0f6Slogwang sizeof(sbuf) - strlen(sbuf), " ");
6953b2bd0f6Slogwang }
6963b2bd0f6Slogwang }
6973b2bd0f6Slogwang snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " ");
6983b2bd0f6Slogwang for (k = 0; k < DUMP_BYTES_PER_LINE; k++) {
6993b2bd0f6Slogwang if (count + k < len) {
7003b2bd0f6Slogwang ch = isprint(buf[count + k]) ?
7013b2bd0f6Slogwang buf[count + k] : '.';
7023b2bd0f6Slogwang snprintf(sbuf + strlen(sbuf),
7033b2bd0f6Slogwang sizeof(sbuf) - strlen(sbuf), "%c", ch);
7043b2bd0f6Slogwang } else {
7053b2bd0f6Slogwang snprintf(sbuf + strlen(sbuf),
7063b2bd0f6Slogwang sizeof(sbuf) - strlen(sbuf), " ");
7073b2bd0f6Slogwang }
7083b2bd0f6Slogwang }
7093b2bd0f6Slogwang printf("%s\n", sbuf);
7103b2bd0f6Slogwang }
7113b2bd0f6Slogwang }
7123b2bd0f6Slogwang
7133b2bd0f6Slogwang /*
7143b2bd0f6Slogwang * Usage()
7153b2bd0f6Slogwang */
7163b2bd0f6Slogwang static void
7173b2bd0f6Slogwang Usage(const char *msg)
7183b2bd0f6Slogwang {
7193b2bd0f6Slogwang if (msg)
7203b2bd0f6Slogwang warnx("%s", msg);
7213b2bd0f6Slogwang fprintf(stderr,
722*d4a07e70Sfengbojiang #ifndef FSTACK
7233b2bd0f6Slogwang "usage: ngctl [-d] [-f file] [-n name] [command ...]\n");
724*d4a07e70Sfengbojiang #else
725*d4a07e70Sfengbojiang "usage: ngctl -p <f-stack proc_id> [-d] [-f file] [-n name] [command ...]\n");
726*d4a07e70Sfengbojiang
727*d4a07e70Sfengbojiang ff_ipc_exit();
728*d4a07e70Sfengbojiang #endif
7293b2bd0f6Slogwang exit(EX_USAGE);
7303b2bd0f6Slogwang }
731