14cf49a43SJulian Elischer 24cf49a43SJulian Elischer /* 34cf49a43SJulian Elischer * main.c 44cf49a43SJulian Elischer * 54cf49a43SJulian Elischer * Copyright (c) 1996-1999 Whistle Communications, Inc. 64cf49a43SJulian Elischer * All rights reserved. 74cf49a43SJulian Elischer * 84cf49a43SJulian Elischer * Subject to the following obligations and disclaimer of warranty, use and 94cf49a43SJulian Elischer * redistribution of this software, in source or object code forms, with or 104cf49a43SJulian Elischer * without modifications are expressly permitted by Whistle Communications; 114cf49a43SJulian Elischer * provided, however, that: 124cf49a43SJulian Elischer * 1. Any and all reproductions of the source or object code must include the 134cf49a43SJulian Elischer * copyright notice above and the following disclaimer of warranties; and 144cf49a43SJulian Elischer * 2. No rights are granted, in any manner or form, to use Whistle 154cf49a43SJulian Elischer * Communications, Inc. trademarks, including the mark "WHISTLE 164cf49a43SJulian Elischer * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 174cf49a43SJulian Elischer * such appears in the above copyright notice or in the software. 184cf49a43SJulian Elischer * 194cf49a43SJulian Elischer * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 204cf49a43SJulian Elischer * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 214cf49a43SJulian Elischer * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 224cf49a43SJulian Elischer * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 234cf49a43SJulian Elischer * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 244cf49a43SJulian Elischer * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 254cf49a43SJulian Elischer * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 264cf49a43SJulian Elischer * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 274cf49a43SJulian Elischer * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 284cf49a43SJulian Elischer * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 294cf49a43SJulian Elischer * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 304cf49a43SJulian Elischer * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 314cf49a43SJulian Elischer * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 324cf49a43SJulian Elischer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 334cf49a43SJulian Elischer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 344cf49a43SJulian Elischer * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 354cf49a43SJulian Elischer * OF SUCH DAMAGE. 364cf49a43SJulian Elischer * 37f8307e12SArchie Cobbs * $Whistle: main.c,v 1.12 1999/11/29 19:17:46 archie Exp $ 384cf49a43SJulian Elischer */ 394cf49a43SJulian Elischer 40*d31ff7a8SPhilippe Charnier #include <sys/cdefs.h> 41*d31ff7a8SPhilippe Charnier __FBSDID("$FreeBSD$"); 42*d31ff7a8SPhilippe Charnier 4378cdd8edSGleb Smirnoff #include <sys/param.h> 4478cdd8edSGleb Smirnoff #include <sys/socket.h> 4578cdd8edSGleb Smirnoff #include <sys/select.h> 4678cdd8edSGleb Smirnoff 4778cdd8edSGleb Smirnoff #include <ctype.h> 4878cdd8edSGleb Smirnoff #include <err.h> 4978cdd8edSGleb Smirnoff #include <errno.h> 5078cdd8edSGleb Smirnoff #include <limits.h> 5178cdd8edSGleb Smirnoff #include <stdio.h> 5278cdd8edSGleb Smirnoff #include <stdlib.h> 5378cdd8edSGleb Smirnoff #include <string.h> 5478cdd8edSGleb Smirnoff #include <sysexits.h> 5578cdd8edSGleb Smirnoff #include <unistd.h> 56b9124a73SGleb Smirnoff #ifdef EDITLINE 57b9124a73SGleb Smirnoff #include <signal.h> 58b9124a73SGleb Smirnoff #include <histedit.h> 59b9124a73SGleb Smirnoff #include <pthread.h> 60b9124a73SGleb Smirnoff #endif 6178cdd8edSGleb Smirnoff 6278cdd8edSGleb Smirnoff #include <netgraph.h> 6378cdd8edSGleb Smirnoff 644cf49a43SJulian Elischer #include "ngctl.h" 654cf49a43SJulian Elischer 664cf49a43SJulian Elischer #define PROMPT "+ " 674cf49a43SJulian Elischer #define MAX_ARGS 512 684cf49a43SJulian Elischer #define WHITESPACE " \t\r\n\v\f" 69f8307e12SArchie Cobbs #define DUMP_BYTES_PER_LINE 16 704cf49a43SJulian Elischer 714cf49a43SJulian Elischer /* Internal functions */ 724cf49a43SJulian Elischer static int ReadFile(FILE *fp); 73eac2afceSGleb Smirnoff static void ReadSockets(fd_set *); 7448b5fd63SMike Makonnen static int DoParseCommand(const char *line); 754cf49a43SJulian Elischer static int DoCommand(int ac, char **av); 764cf49a43SJulian Elischer static int DoInteractive(void); 774cf49a43SJulian Elischer static const struct ngcmd *FindCommand(const char *string); 78f8307e12SArchie Cobbs static int MatchCommand(const struct ngcmd *cmd, const char *s); 794cf49a43SJulian Elischer static void Usage(const char *msg); 804cf49a43SJulian Elischer static int ReadCmd(int ac, char **av); 814cf49a43SJulian Elischer static int HelpCmd(int ac, char **av); 824cf49a43SJulian Elischer static int QuitCmd(int ac, char **av); 83b9124a73SGleb Smirnoff #ifdef EDITLINE 84c5401464SDag-Erling Smørgrav static volatile sig_atomic_t unblock; 85b9124a73SGleb Smirnoff static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 86b9124a73SGleb Smirnoff static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 87b9124a73SGleb Smirnoff #endif 884cf49a43SJulian Elischer 894cf49a43SJulian Elischer /* List of commands */ 904cf49a43SJulian Elischer static const struct ngcmd *const cmds[] = { 917095e097SPoul-Henning Kamp &config_cmd, 924cf49a43SJulian Elischer &connect_cmd, 934cf49a43SJulian Elischer &debug_cmd, 94bbd6d60aSBrian Feldman &dot_cmd, 954cf49a43SJulian Elischer &help_cmd, 964cf49a43SJulian Elischer &list_cmd, 974cf49a43SJulian Elischer &mkpeer_cmd, 98f8307e12SArchie Cobbs &msg_cmd, 994cf49a43SJulian Elischer &name_cmd, 1004cf49a43SJulian Elischer &read_cmd, 1014cf49a43SJulian Elischer &rmhook_cmd, 1024cf49a43SJulian Elischer &show_cmd, 1034cf49a43SJulian Elischer &shutdown_cmd, 1044cf49a43SJulian Elischer &status_cmd, 1054cf49a43SJulian Elischer &types_cmd, 106be44fce4SArchie Cobbs &write_cmd, 1074cf49a43SJulian Elischer &quit_cmd, 1084cf49a43SJulian Elischer NULL 1094cf49a43SJulian Elischer }; 1104cf49a43SJulian Elischer 1114cf49a43SJulian Elischer /* Commands defined in this file */ 1124cf49a43SJulian Elischer const struct ngcmd read_cmd = { 1134cf49a43SJulian Elischer ReadCmd, 1144cf49a43SJulian Elischer "read <filename>", 1154cf49a43SJulian Elischer "Read and execute commands from a file", 116f8307e12SArchie Cobbs NULL, 117f8307e12SArchie Cobbs { "source", "." } 1184cf49a43SJulian Elischer }; 1194cf49a43SJulian Elischer const struct ngcmd help_cmd = { 1204cf49a43SJulian Elischer HelpCmd, 1214cf49a43SJulian Elischer "help [command]", 1224cf49a43SJulian Elischer "Show command summary or get more help on a specific command", 123f8307e12SArchie Cobbs NULL, 124f8307e12SArchie Cobbs { "?" } 1254cf49a43SJulian Elischer }; 1264cf49a43SJulian Elischer const struct ngcmd quit_cmd = { 1274cf49a43SJulian Elischer QuitCmd, 1284cf49a43SJulian Elischer "quit", 1294cf49a43SJulian Elischer "Exit program", 130f8307e12SArchie Cobbs NULL, 131f8307e12SArchie Cobbs { "exit" } 1324cf49a43SJulian Elischer }; 1334cf49a43SJulian Elischer 1344cf49a43SJulian Elischer /* Our control and data sockets */ 1354cf49a43SJulian Elischer int csock, dsock; 1364cf49a43SJulian Elischer 1374cf49a43SJulian Elischer /* 1384cf49a43SJulian Elischer * main() 1394cf49a43SJulian Elischer */ 1404cf49a43SJulian Elischer int 1414cf49a43SJulian Elischer main(int ac, char *av[]) 1424cf49a43SJulian Elischer { 1439d901d3bSHartmut Brandt char name[NG_NODESIZ]; 1444cf49a43SJulian Elischer int interactive = isatty(0) && isatty(1); 1454cf49a43SJulian Elischer FILE *fp = NULL; 146c44e20ebSMaxim Konovalov int ch, rtn = 0; 1474cf49a43SJulian Elischer 1484cf49a43SJulian Elischer /* Set default node name */ 1494cf49a43SJulian Elischer snprintf(name, sizeof(name), "ngctl%d", getpid()); 1504cf49a43SJulian Elischer 1514cf49a43SJulian Elischer /* Parse command line */ 1529c20ad30SKevin Lo while ((ch = getopt(ac, av, "df:n:")) != -1) { 1534cf49a43SJulian Elischer switch (ch) { 1544cf49a43SJulian Elischer case 'd': 1554cf49a43SJulian Elischer NgSetDebug(NgSetDebug(-1) + 1); 1564cf49a43SJulian Elischer break; 1574cf49a43SJulian Elischer case 'f': 1584cf49a43SJulian Elischer if (strcmp(optarg, "-") == 0) 1594cf49a43SJulian Elischer fp = stdin; 1604cf49a43SJulian Elischer else if ((fp = fopen(optarg, "r")) == NULL) 1614cf49a43SJulian Elischer err(EX_NOINPUT, "%s", optarg); 1624cf49a43SJulian Elischer break; 1634cf49a43SJulian Elischer case 'n': 1644cf49a43SJulian Elischer snprintf(name, sizeof(name), "%s", optarg); 1654cf49a43SJulian Elischer break; 1664cf49a43SJulian Elischer case '?': 1674cf49a43SJulian Elischer default: 1684cf49a43SJulian Elischer Usage((char *)NULL); 1694cf49a43SJulian Elischer break; 1704cf49a43SJulian Elischer } 1714cf49a43SJulian Elischer } 1724cf49a43SJulian Elischer ac -= optind; 1734cf49a43SJulian Elischer av += optind; 1744cf49a43SJulian Elischer 1754cf49a43SJulian Elischer /* Create a new socket node */ 176b08b2814SArchie Cobbs if (NgMkSockNode(name, &csock, &dsock) < 0) 1774cf49a43SJulian Elischer err(EX_OSERR, "can't create node"); 178c44e20ebSMaxim Konovalov 1794cf49a43SJulian Elischer /* Do commands as requested */ 1804cf49a43SJulian Elischer if (ac == 0) { 1814cf49a43SJulian Elischer if (fp != NULL) { 1824cf49a43SJulian Elischer rtn = ReadFile(fp); 1834cf49a43SJulian Elischer } else if (interactive) { 1844cf49a43SJulian Elischer rtn = DoInteractive(); 1854cf49a43SJulian Elischer } else 1864cf49a43SJulian Elischer Usage("no command specified"); 1874cf49a43SJulian Elischer } else { 1884cf49a43SJulian Elischer rtn = DoCommand(ac, av); 1894cf49a43SJulian Elischer } 1904cf49a43SJulian Elischer 1914cf49a43SJulian Elischer /* Convert command return code into system exit code */ 1924cf49a43SJulian Elischer switch (rtn) { 1934cf49a43SJulian Elischer case CMDRTN_OK: 1944cf49a43SJulian Elischer case CMDRTN_QUIT: 1954cf49a43SJulian Elischer rtn = 0; 1964cf49a43SJulian Elischer break; 1974cf49a43SJulian Elischer case CMDRTN_USAGE: 1984cf49a43SJulian Elischer rtn = EX_USAGE; 1994cf49a43SJulian Elischer break; 2004cf49a43SJulian Elischer case CMDRTN_ERROR: 2014cf49a43SJulian Elischer rtn = EX_OSERR; 2024cf49a43SJulian Elischer break; 2034cf49a43SJulian Elischer } 2044cf49a43SJulian Elischer return (rtn); 2054cf49a43SJulian Elischer } 2064cf49a43SJulian Elischer 2074cf49a43SJulian Elischer /* 2084cf49a43SJulian Elischer * Process commands from a file 2094cf49a43SJulian Elischer */ 2104cf49a43SJulian Elischer static int 2114cf49a43SJulian Elischer ReadFile(FILE *fp) 2124cf49a43SJulian Elischer { 2134cf49a43SJulian Elischer char line[LINE_MAX]; 2144cf49a43SJulian Elischer int num, rtn; 2154cf49a43SJulian Elischer 2164cf49a43SJulian Elischer for (num = 1; fgets(line, sizeof(line), fp) != NULL; num++) { 2174cf49a43SJulian Elischer if (*line == '#') 2184cf49a43SJulian Elischer continue; 2194cf49a43SJulian Elischer if ((rtn = DoParseCommand(line)) != 0) { 2204cf49a43SJulian Elischer warnx("line %d: error in file", num); 2214cf49a43SJulian Elischer return (rtn); 2224cf49a43SJulian Elischer } 2234cf49a43SJulian Elischer } 2244cf49a43SJulian Elischer return (CMDRTN_OK); 2254cf49a43SJulian Elischer } 2264cf49a43SJulian Elischer 227b9124a73SGleb Smirnoff #ifdef EDITLINE 228b9124a73SGleb Smirnoff /* Signal handler for Monitor() thread. */ 229b9124a73SGleb Smirnoff static void 230*d31ff7a8SPhilippe Charnier Unblock(int signal __unused) 231b9124a73SGleb Smirnoff { 232eac2afceSGleb Smirnoff 233b9124a73SGleb Smirnoff unblock = 1; 234b9124a73SGleb Smirnoff } 235b9124a73SGleb Smirnoff 2364cf49a43SJulian Elischer /* 237b9124a73SGleb Smirnoff * Thread that monitors csock and dsock while main thread 238b9124a73SGleb Smirnoff * can be blocked in el_gets(). 239b9124a73SGleb Smirnoff */ 240b9124a73SGleb Smirnoff static void * 241*d31ff7a8SPhilippe Charnier Monitor(void *v __unused) 242b9124a73SGleb Smirnoff { 243b9124a73SGleb Smirnoff struct sigaction act; 244b9124a73SGleb Smirnoff const int maxfd = MAX(csock, dsock) + 1; 245b9124a73SGleb Smirnoff 246b9124a73SGleb Smirnoff act.sa_handler = Unblock; 247b9124a73SGleb Smirnoff sigemptyset(&act.sa_mask); 248b9124a73SGleb Smirnoff act.sa_flags = 0; 249b9124a73SGleb Smirnoff sigaction(SIGUSR1, &act, NULL); 250b9124a73SGleb Smirnoff 251b9124a73SGleb Smirnoff pthread_mutex_lock(&mutex); 252b9124a73SGleb Smirnoff for (;;) { 253b9124a73SGleb Smirnoff fd_set rfds; 254b9124a73SGleb Smirnoff 255b9124a73SGleb Smirnoff /* See if any data or control messages are arriving. */ 256b9124a73SGleb Smirnoff FD_ZERO(&rfds); 257b9124a73SGleb Smirnoff FD_SET(csock, &rfds); 258b9124a73SGleb Smirnoff FD_SET(dsock, &rfds); 259b9124a73SGleb Smirnoff unblock = 0; 260b9124a73SGleb Smirnoff if (select(maxfd, &rfds, NULL, NULL, NULL) <= 0) { 261b9124a73SGleb Smirnoff if (errno == EINTR) { 262b9124a73SGleb Smirnoff if (unblock == 1) 263b9124a73SGleb Smirnoff pthread_cond_wait(&cond, &mutex); 264b9124a73SGleb Smirnoff continue; 265b9124a73SGleb Smirnoff } 266b9124a73SGleb Smirnoff err(EX_OSERR, "select"); 267b9124a73SGleb Smirnoff } 268eac2afceSGleb Smirnoff ReadSockets(&rfds); 269b9124a73SGleb Smirnoff } 270b9124a73SGleb Smirnoff 271b9124a73SGleb Smirnoff return (NULL); 272b9124a73SGleb Smirnoff } 273b9124a73SGleb Smirnoff 274b9124a73SGleb Smirnoff static char * 275*d31ff7a8SPhilippe Charnier Prompt(EditLine *el __unused) 276b9124a73SGleb Smirnoff { 277eac2afceSGleb Smirnoff 278eac2afceSGleb Smirnoff return (PROMPT); 279b9124a73SGleb Smirnoff } 280b9124a73SGleb Smirnoff 281b9124a73SGleb Smirnoff /* 282b9124a73SGleb Smirnoff * Here we start a thread, that will monitor the netgraph 283b9124a73SGleb Smirnoff * sockets and catch any unexpected messages or data on them, 284b9124a73SGleb Smirnoff * that can arrive while user edits his/her commands. 285b9124a73SGleb Smirnoff * 286b9124a73SGleb Smirnoff * Whenever we expect data on netgraph sockets, we send signal 287b9124a73SGleb Smirnoff * to monitoring thread. The signal forces it to exit select() 288b9124a73SGleb Smirnoff * system call and sleep on condvar until we wake it. While 289b9124a73SGleb Smirnoff * monitoring thread sleeps, we can do our work with netgraph 290b9124a73SGleb Smirnoff * sockets. 291b9124a73SGleb Smirnoff */ 292b9124a73SGleb Smirnoff static int 293b9124a73SGleb Smirnoff DoInteractive(void) 294b9124a73SGleb Smirnoff { 295b9124a73SGleb Smirnoff pthread_t monitor; 296b9124a73SGleb Smirnoff EditLine *el; 297b9124a73SGleb Smirnoff History *hist; 298b9124a73SGleb Smirnoff HistEvent hev = { 0, "" }; 299b9124a73SGleb Smirnoff 300b9124a73SGleb Smirnoff (*help_cmd.func)(0, NULL); 301b9124a73SGleb Smirnoff pthread_create(&monitor, NULL, Monitor, NULL); 302b9124a73SGleb Smirnoff el = el_init(getprogname(), stdin, stdout, stderr); 303b9124a73SGleb Smirnoff if (el == NULL) 304b9124a73SGleb Smirnoff return (CMDRTN_ERROR); 305b9124a73SGleb Smirnoff el_set(el, EL_PROMPT, Prompt); 306b9124a73SGleb Smirnoff el_set(el, EL_SIGNAL, 1); 307b9124a73SGleb Smirnoff el_set(el, EL_EDITOR, "emacs"); 308b9124a73SGleb Smirnoff hist = history_init(); 309b9124a73SGleb Smirnoff if (hist == NULL) 310b9124a73SGleb Smirnoff return (CMDRTN_ERROR); 311b9124a73SGleb Smirnoff history(hist, &hev, H_SETSIZE, 100); 312b9124a73SGleb Smirnoff history(hist, &hev, H_SETUNIQUE, 1); 313b9124a73SGleb Smirnoff el_set(el, EL_HIST, history, (const char *)hist); 314b9124a73SGleb Smirnoff el_source(el, NULL); 315b9124a73SGleb Smirnoff 316b9124a73SGleb Smirnoff for (;;) { 317b9124a73SGleb Smirnoff const char *buf; 318b9124a73SGleb Smirnoff int count; 319b9124a73SGleb Smirnoff 320b9124a73SGleb Smirnoff if ((buf = el_gets(el, &count)) == NULL) { 321b9124a73SGleb Smirnoff printf("\n"); 322b9124a73SGleb Smirnoff break; 323b9124a73SGleb Smirnoff } 324b9124a73SGleb Smirnoff history(hist, &hev, H_ENTER, buf); 325b9124a73SGleb Smirnoff pthread_kill(monitor, SIGUSR1); 326b9124a73SGleb Smirnoff pthread_mutex_lock(&mutex); 32748b5fd63SMike Makonnen if (DoParseCommand(buf) == CMDRTN_QUIT) 328b9124a73SGleb Smirnoff break; 329b9124a73SGleb Smirnoff pthread_cond_signal(&cond); 330b9124a73SGleb Smirnoff pthread_mutex_unlock(&mutex); 331b9124a73SGleb Smirnoff } 332b9124a73SGleb Smirnoff 333b9124a73SGleb Smirnoff history_end(hist); 334b9124a73SGleb Smirnoff el_end(el); 335b9124a73SGleb Smirnoff pthread_cancel(monitor); 336b9124a73SGleb Smirnoff 337b9124a73SGleb Smirnoff return (CMDRTN_QUIT); 338b9124a73SGleb Smirnoff } 339b9124a73SGleb Smirnoff 340b9124a73SGleb Smirnoff #else /* !EDITLINE */ 341b9124a73SGleb Smirnoff 342b9124a73SGleb Smirnoff /* 343b9124a73SGleb Smirnoff * Interactive mode w/o libedit functionality. 3444cf49a43SJulian Elischer */ 3454cf49a43SJulian Elischer static int 3464cf49a43SJulian Elischer DoInteractive(void) 3474cf49a43SJulian Elischer { 348f8307e12SArchie Cobbs const int maxfd = MAX(csock, dsock) + 1; 349f8307e12SArchie Cobbs 350f8307e12SArchie Cobbs (*help_cmd.func)(0, NULL); 351f8307e12SArchie Cobbs while (1) { 352f8307e12SArchie Cobbs struct timeval tv; 353f8307e12SArchie Cobbs fd_set rfds; 354f8307e12SArchie Cobbs 355f8307e12SArchie Cobbs /* See if any data or control messages are arriving */ 356f8307e12SArchie Cobbs FD_ZERO(&rfds); 357f8307e12SArchie Cobbs FD_SET(csock, &rfds); 358f8307e12SArchie Cobbs FD_SET(dsock, &rfds); 359f8307e12SArchie Cobbs memset(&tv, 0, sizeof(tv)); 360f8307e12SArchie Cobbs if (select(maxfd, &rfds, NULL, NULL, &tv) <= 0) { 361f8307e12SArchie Cobbs 362f8307e12SArchie Cobbs /* Issue prompt and wait for anything to happen */ 363f8307e12SArchie Cobbs printf("%s", PROMPT); 364f8307e12SArchie Cobbs fflush(stdout); 365f8307e12SArchie Cobbs FD_ZERO(&rfds); 366f8307e12SArchie Cobbs FD_SET(0, &rfds); 367f8307e12SArchie Cobbs FD_SET(csock, &rfds); 368f8307e12SArchie Cobbs FD_SET(dsock, &rfds); 369f8307e12SArchie Cobbs if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) 370f8307e12SArchie Cobbs err(EX_OSERR, "select"); 371f8307e12SArchie Cobbs 372f8307e12SArchie Cobbs /* If not user input, print a newline first */ 373f8307e12SArchie Cobbs if (!FD_ISSET(0, &rfds)) 374f8307e12SArchie Cobbs printf("\n"); 375f8307e12SArchie Cobbs } 376f8307e12SArchie Cobbs 377eac2afceSGleb Smirnoff ReadSockets(&rfds); 378f8307e12SArchie Cobbs 379f8307e12SArchie Cobbs /* Get any user input */ 380f8307e12SArchie Cobbs if (FD_ISSET(0, &rfds)) { 3810c5c7719SPoul-Henning Kamp char buf[LINE_MAX]; 3820c5c7719SPoul-Henning Kamp 3830c5c7719SPoul-Henning Kamp if (fgets(buf, sizeof(buf), stdin) == NULL) { 3840c5c7719SPoul-Henning Kamp printf("\n"); 3850c5c7719SPoul-Henning Kamp break; 3860c5c7719SPoul-Henning Kamp } 3870c5c7719SPoul-Henning Kamp if (DoParseCommand(buf) == CMDRTN_QUIT) 388f8307e12SArchie Cobbs break; 389f8307e12SArchie Cobbs } 390f8307e12SArchie Cobbs } 3914cf49a43SJulian Elischer return (CMDRTN_QUIT); 3924cf49a43SJulian Elischer } 393b9124a73SGleb Smirnoff #endif /* !EDITLINE */ 394b9124a73SGleb Smirnoff 395b9124a73SGleb Smirnoff /* 396b9124a73SGleb Smirnoff * Read and process data on netgraph control and data sockets. 397b9124a73SGleb Smirnoff */ 398b9124a73SGleb Smirnoff static void 399eac2afceSGleb Smirnoff ReadSockets(fd_set *rfds) 400b9124a73SGleb Smirnoff { 401b9124a73SGleb Smirnoff /* Display any incoming control message. */ 402eac2afceSGleb Smirnoff if (FD_ISSET(csock, rfds)) 403b9124a73SGleb Smirnoff MsgRead(); 404b9124a73SGleb Smirnoff 405b9124a73SGleb Smirnoff /* Display any incoming data packet. */ 406eac2afceSGleb Smirnoff if (FD_ISSET(dsock, rfds)) { 407b9124a73SGleb Smirnoff char hook[NG_HOOKSIZ]; 408b9124a73SGleb Smirnoff u_char *buf; 409b9124a73SGleb Smirnoff int rl; 410b9124a73SGleb Smirnoff 411b9124a73SGleb Smirnoff /* Read packet from socket. */ 412b9124a73SGleb Smirnoff if ((rl = NgAllocRecvData(dsock, &buf, hook)) < 0) 413b9124a73SGleb Smirnoff err(EX_OSERR, "reading hook \"%s\"", hook); 414b9124a73SGleb Smirnoff if (rl == 0) 415b9124a73SGleb Smirnoff errx(EX_OSERR, "EOF from hook \"%s\"?", hook); 416b9124a73SGleb Smirnoff 417b9124a73SGleb Smirnoff /* Write packet to stdout. */ 418b9124a73SGleb Smirnoff printf("Rec'd data packet on hook \"%s\":\n", hook); 419b9124a73SGleb Smirnoff DumpAscii(buf, rl); 420b9124a73SGleb Smirnoff free(buf); 421b9124a73SGleb Smirnoff } 422b9124a73SGleb Smirnoff } 4234cf49a43SJulian Elischer 4244cf49a43SJulian Elischer /* 4254cf49a43SJulian Elischer * Parse a command line and execute the command 4264cf49a43SJulian Elischer */ 4274cf49a43SJulian Elischer static int 42848b5fd63SMike Makonnen DoParseCommand(const char *line) 4294cf49a43SJulian Elischer { 4304cf49a43SJulian Elischer char *av[MAX_ARGS]; 4314cf49a43SJulian Elischer int ac; 4324cf49a43SJulian Elischer 4334cf49a43SJulian Elischer /* Parse line */ 43448b5fd63SMike Makonnen for (ac = 0, av[0] = strtok((char *)line, WHITESPACE); 4354cf49a43SJulian Elischer ac < MAX_ARGS - 1 && av[ac]; 4364cf49a43SJulian Elischer av[++ac] = strtok(NULL, WHITESPACE)); 4374cf49a43SJulian Elischer 4384cf49a43SJulian Elischer /* Do command */ 4394cf49a43SJulian Elischer return (DoCommand(ac, av)); 4404cf49a43SJulian Elischer } 4414cf49a43SJulian Elischer 4424cf49a43SJulian Elischer /* 4434cf49a43SJulian Elischer * Execute the command 4444cf49a43SJulian Elischer */ 4454cf49a43SJulian Elischer static int 4464cf49a43SJulian Elischer DoCommand(int ac, char **av) 4474cf49a43SJulian Elischer { 4484cf49a43SJulian Elischer const struct ngcmd *cmd; 4494cf49a43SJulian Elischer int rtn; 4504cf49a43SJulian Elischer 4514cf49a43SJulian Elischer if (ac == 0 || *av[0] == 0) 4524cf49a43SJulian Elischer return (CMDRTN_OK); 4534cf49a43SJulian Elischer if ((cmd = FindCommand(av[0])) == NULL) 4544cf49a43SJulian Elischer return (CMDRTN_ERROR); 4554cf49a43SJulian Elischer if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE) 4564cf49a43SJulian Elischer warnx("usage: %s", cmd->cmd); 4574cf49a43SJulian Elischer return (rtn); 4584cf49a43SJulian Elischer } 4594cf49a43SJulian Elischer 4604cf49a43SJulian Elischer /* 4614cf49a43SJulian Elischer * Find a command 4624cf49a43SJulian Elischer */ 4634cf49a43SJulian Elischer static const struct ngcmd * 4644cf49a43SJulian Elischer FindCommand(const char *string) 4654cf49a43SJulian Elischer { 466f8307e12SArchie Cobbs int k, found = -1; 4674cf49a43SJulian Elischer 468f8307e12SArchie Cobbs for (k = 0; cmds[k] != NULL; k++) { 469f8307e12SArchie Cobbs if (MatchCommand(cmds[k], string)) { 4704cf49a43SJulian Elischer if (found != -1) { 4714cf49a43SJulian Elischer warnx("\"%s\": ambiguous command", string); 4724cf49a43SJulian Elischer return (NULL); 4734cf49a43SJulian Elischer } 4744cf49a43SJulian Elischer found = k; 4754cf49a43SJulian Elischer } 4764cf49a43SJulian Elischer } 4774cf49a43SJulian Elischer if (found == -1) { 4784cf49a43SJulian Elischer warnx("\"%s\": unknown command", string); 4794cf49a43SJulian Elischer return (NULL); 4804cf49a43SJulian Elischer } 4814cf49a43SJulian Elischer return (cmds[found]); 4824cf49a43SJulian Elischer } 4834cf49a43SJulian Elischer 4844cf49a43SJulian Elischer /* 485f8307e12SArchie Cobbs * See if string matches a prefix of "cmd" (or an alias) case insensitively 486f8307e12SArchie Cobbs */ 487f8307e12SArchie Cobbs static int 488f8307e12SArchie Cobbs MatchCommand(const struct ngcmd *cmd, const char *s) 489f8307e12SArchie Cobbs { 490f8307e12SArchie Cobbs int a; 491f8307e12SArchie Cobbs 492f8307e12SArchie Cobbs /* Try to match command, ignoring the usage stuff */ 493f8307e12SArchie Cobbs if (strlen(s) <= strcspn(cmd->cmd, WHITESPACE)) { 494f8307e12SArchie Cobbs if (strncasecmp(s, cmd->cmd, strlen(s)) == 0) 495f8307e12SArchie Cobbs return (1); 496f8307e12SArchie Cobbs } 497f8307e12SArchie Cobbs 498f8307e12SArchie Cobbs /* Try to match aliases */ 499f8307e12SArchie Cobbs for (a = 0; a < MAX_CMD_ALIAS && cmd->aliases[a] != NULL; a++) { 500f8307e12SArchie Cobbs if (strlen(cmd->aliases[a]) >= strlen(s)) { 501f8307e12SArchie Cobbs if (strncasecmp(s, cmd->aliases[a], strlen(s)) == 0) 502f8307e12SArchie Cobbs return (1); 503f8307e12SArchie Cobbs } 504f8307e12SArchie Cobbs } 505f8307e12SArchie Cobbs 506f8307e12SArchie Cobbs /* No match */ 507f8307e12SArchie Cobbs return (0); 508f8307e12SArchie Cobbs } 509f8307e12SArchie Cobbs 510f8307e12SArchie Cobbs /* 5114cf49a43SJulian Elischer * ReadCmd() 5124cf49a43SJulian Elischer */ 5134cf49a43SJulian Elischer static int 5144cf49a43SJulian Elischer ReadCmd(int ac, char **av) 5154cf49a43SJulian Elischer { 5164cf49a43SJulian Elischer FILE *fp; 5174cf49a43SJulian Elischer int rtn; 5184cf49a43SJulian Elischer 5194cf49a43SJulian Elischer /* Open file */ 5204cf49a43SJulian Elischer switch (ac) { 5214cf49a43SJulian Elischer case 2: 522f35e82dfSArchie Cobbs if ((fp = fopen(av[1], "r")) == NULL) { 5234cf49a43SJulian Elischer warn("%s", av[1]); 5244cf49a43SJulian Elischer return (CMDRTN_ERROR); 525f35e82dfSArchie Cobbs } 526f35e82dfSArchie Cobbs break; 5274cf49a43SJulian Elischer default: 5284cf49a43SJulian Elischer return (CMDRTN_USAGE); 5294cf49a43SJulian Elischer } 5304cf49a43SJulian Elischer 5314cf49a43SJulian Elischer /* Process it */ 5324cf49a43SJulian Elischer rtn = ReadFile(fp); 5334cf49a43SJulian Elischer fclose(fp); 5344cf49a43SJulian Elischer return (rtn); 5354cf49a43SJulian Elischer } 5364cf49a43SJulian Elischer 5374cf49a43SJulian Elischer /* 5384cf49a43SJulian Elischer * HelpCmd() 5394cf49a43SJulian Elischer */ 5404cf49a43SJulian Elischer static int 5414cf49a43SJulian Elischer HelpCmd(int ac, char **av) 5424cf49a43SJulian Elischer { 5434cf49a43SJulian Elischer const struct ngcmd *cmd; 5444cf49a43SJulian Elischer int k; 5454cf49a43SJulian Elischer 5464cf49a43SJulian Elischer switch (ac) { 5474cf49a43SJulian Elischer case 0: 5484cf49a43SJulian Elischer case 1: 5494cf49a43SJulian Elischer /* Show all commands */ 5504cf49a43SJulian Elischer printf("Available commands:\n"); 5514cf49a43SJulian Elischer for (k = 0; cmds[k] != NULL; k++) { 5524cf49a43SJulian Elischer char *s, buf[100]; 5534cf49a43SJulian Elischer 5544cf49a43SJulian Elischer cmd = cmds[k]; 5554cf49a43SJulian Elischer snprintf(buf, sizeof(buf), "%s", cmd->cmd); 5564cf49a43SJulian Elischer for (s = buf; *s != '\0' && !isspace(*s); s++); 5574cf49a43SJulian Elischer *s = '\0'; 5584cf49a43SJulian Elischer printf(" %-10s %s\n", buf, cmd->desc); 5594cf49a43SJulian Elischer } 5604cf49a43SJulian Elischer return (CMDRTN_OK); 5614cf49a43SJulian Elischer default: 5624cf49a43SJulian Elischer /* Show help on a specific command */ 5634cf49a43SJulian Elischer if ((cmd = FindCommand(av[1])) != NULL) { 564d3974088SDag-Erling Smørgrav printf("usage: %s\n", cmd->cmd); 565f8307e12SArchie Cobbs if (cmd->aliases[0] != NULL) { 566f8307e12SArchie Cobbs int a = 0; 567f8307e12SArchie Cobbs 568f8307e12SArchie Cobbs printf("Aliases: "); 569f8307e12SArchie Cobbs while (1) { 570f8307e12SArchie Cobbs printf("%s", cmd->aliases[a++]); 571f8307e12SArchie Cobbs if (a == MAX_CMD_ALIAS 572f8307e12SArchie Cobbs || cmd->aliases[a] == NULL) { 573f8307e12SArchie Cobbs printf("\n"); 574f8307e12SArchie Cobbs break; 575f8307e12SArchie Cobbs } 576f8307e12SArchie Cobbs printf(", "); 577f8307e12SArchie Cobbs } 578f8307e12SArchie Cobbs } 5794cf49a43SJulian Elischer printf("Summary: %s\n", cmd->desc); 5804cf49a43SJulian Elischer if (cmd->help != NULL) { 5814cf49a43SJulian Elischer const char *s; 5824cf49a43SJulian Elischer char buf[65]; 5834cf49a43SJulian Elischer int tot, len, done; 5844cf49a43SJulian Elischer 5854cf49a43SJulian Elischer printf("Description:\n"); 5864cf49a43SJulian Elischer for (s = cmd->help; *s != '\0'; s += len) { 5874cf49a43SJulian Elischer while (isspace(*s)) 5884cf49a43SJulian Elischer s++; 5894cf49a43SJulian Elischer tot = snprintf(buf, 5904cf49a43SJulian Elischer sizeof(buf), "%s", s); 5914cf49a43SJulian Elischer len = strlen(buf); 5924cf49a43SJulian Elischer done = len == tot; 5934cf49a43SJulian Elischer if (!done) { 5944cf49a43SJulian Elischer while (len > 0 5954cf49a43SJulian Elischer && !isspace(buf[len-1])) 5964cf49a43SJulian Elischer buf[--len] = '\0'; 5974cf49a43SJulian Elischer } 5984cf49a43SJulian Elischer printf(" %s\n", buf); 5994cf49a43SJulian Elischer } 6004cf49a43SJulian Elischer } 6014cf49a43SJulian Elischer } 6024cf49a43SJulian Elischer } 6034cf49a43SJulian Elischer return (CMDRTN_OK); 6044cf49a43SJulian Elischer } 6054cf49a43SJulian Elischer 6064cf49a43SJulian Elischer /* 6074cf49a43SJulian Elischer * QuitCmd() 6084cf49a43SJulian Elischer */ 6094cf49a43SJulian Elischer static int 610723c1c2eSRuslan Ermilov QuitCmd(int ac __unused, char **av __unused) 6114cf49a43SJulian Elischer { 6124cf49a43SJulian Elischer return (CMDRTN_QUIT); 6134cf49a43SJulian Elischer } 6144cf49a43SJulian Elischer 6154cf49a43SJulian Elischer /* 616f8307e12SArchie Cobbs * Dump data in hex and ASCII form 617f8307e12SArchie Cobbs */ 6186ebb8ebbSArchie Cobbs void 619f8307e12SArchie Cobbs DumpAscii(const u_char *buf, int len) 620f8307e12SArchie Cobbs { 621f8307e12SArchie Cobbs char ch, sbuf[100]; 622f8307e12SArchie Cobbs int k, count; 623f8307e12SArchie Cobbs 624f8307e12SArchie Cobbs for (count = 0; count < len; count += DUMP_BYTES_PER_LINE) { 625f8307e12SArchie Cobbs snprintf(sbuf, sizeof(sbuf), "%04x: ", count); 626f8307e12SArchie Cobbs for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 627f8307e12SArchie Cobbs if (count + k < len) { 628f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), 629f8307e12SArchie Cobbs sizeof(sbuf) - strlen(sbuf), 630f8307e12SArchie Cobbs "%02x ", buf[count + k]); 631f8307e12SArchie Cobbs } else { 632f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), 633f8307e12SArchie Cobbs sizeof(sbuf) - strlen(sbuf), " "); 634f8307e12SArchie Cobbs } 635f8307e12SArchie Cobbs } 636f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " "); 637f8307e12SArchie Cobbs for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 638f8307e12SArchie Cobbs if (count + k < len) { 639f8307e12SArchie Cobbs ch = isprint(buf[count + k]) ? 640f8307e12SArchie Cobbs buf[count + k] : '.'; 641f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), 642f8307e12SArchie Cobbs sizeof(sbuf) - strlen(sbuf), "%c", ch); 643f8307e12SArchie Cobbs } else { 644f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), 645f8307e12SArchie Cobbs sizeof(sbuf) - strlen(sbuf), " "); 646f8307e12SArchie Cobbs } 647f8307e12SArchie Cobbs } 648f8307e12SArchie Cobbs printf("%s\n", sbuf); 649f8307e12SArchie Cobbs } 650f8307e12SArchie Cobbs } 651f8307e12SArchie Cobbs 652f8307e12SArchie Cobbs /* 6534cf49a43SJulian Elischer * Usage() 6544cf49a43SJulian Elischer */ 6554cf49a43SJulian Elischer static void 6564cf49a43SJulian Elischer Usage(const char *msg) 6574cf49a43SJulian Elischer { 6584cf49a43SJulian Elischer if (msg) 6594cf49a43SJulian Elischer warnx("%s", msg); 660b00304d4SPhilippe Charnier fprintf(stderr, 661b00304d4SPhilippe Charnier "usage: ngctl [-d] [-f file] [-n name] [command ...]\n"); 662b00304d4SPhilippe Charnier exit(EX_USAGE); 6634cf49a43SJulian Elischer } 664