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 * 374cf49a43SJulian Elischer * $FreeBSD$ 38f8307e12SArchie Cobbs * $Whistle: main.c,v 1.12 1999/11/29 19:17:46 archie Exp $ 394cf49a43SJulian Elischer */ 404cf49a43SJulian Elischer 4178cdd8edSGleb Smirnoff #include <sys/param.h> 4278cdd8edSGleb Smirnoff #include <sys/socket.h> 4378cdd8edSGleb Smirnoff #include <sys/select.h> 4478cdd8edSGleb Smirnoff 4578cdd8edSGleb Smirnoff #include <ctype.h> 4678cdd8edSGleb Smirnoff #include <err.h> 4778cdd8edSGleb Smirnoff #include <errno.h> 4878cdd8edSGleb Smirnoff #include <limits.h> 4978cdd8edSGleb Smirnoff #include <stdio.h> 5078cdd8edSGleb Smirnoff #include <stdlib.h> 5178cdd8edSGleb Smirnoff #include <string.h> 5278cdd8edSGleb Smirnoff #include <sysexits.h> 5378cdd8edSGleb Smirnoff #include <unistd.h> 54b9124a73SGleb Smirnoff #ifdef EDITLINE 55b9124a73SGleb Smirnoff #include <signal.h> 56b9124a73SGleb Smirnoff #include <histedit.h> 57b9124a73SGleb Smirnoff #include <pthread.h> 58b9124a73SGleb Smirnoff #endif 5978cdd8edSGleb Smirnoff 6078cdd8edSGleb Smirnoff #include <netgraph.h> 6178cdd8edSGleb Smirnoff 624cf49a43SJulian Elischer #include "ngctl.h" 634cf49a43SJulian Elischer 644cf49a43SJulian Elischer #define PROMPT "+ " 654cf49a43SJulian Elischer #define MAX_ARGS 512 664cf49a43SJulian Elischer #define WHITESPACE " \t\r\n\v\f" 67f8307e12SArchie Cobbs #define DUMP_BYTES_PER_LINE 16 684cf49a43SJulian Elischer 694cf49a43SJulian Elischer /* Internal functions */ 704cf49a43SJulian Elischer static int ReadFile(FILE *fp); 71b9124a73SGleb Smirnoff static void ReadSockets(fd_set); 724cf49a43SJulian Elischer static int DoParseCommand(char *line); 734cf49a43SJulian Elischer static int DoCommand(int ac, char **av); 744cf49a43SJulian Elischer static int DoInteractive(void); 754cf49a43SJulian Elischer static const struct ngcmd *FindCommand(const char *string); 76f8307e12SArchie Cobbs static int MatchCommand(const struct ngcmd *cmd, const char *s); 774cf49a43SJulian Elischer static void Usage(const char *msg); 784cf49a43SJulian Elischer static int ReadCmd(int ac, char **av); 794cf49a43SJulian Elischer static int HelpCmd(int ac, char **av); 804cf49a43SJulian Elischer static int QuitCmd(int ac, char **av); 81b9124a73SGleb Smirnoff #ifdef EDITLINE 82b9124a73SGleb Smirnoff static sig_atomic_t unblock; 83b9124a73SGleb Smirnoff static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 84b9124a73SGleb Smirnoff static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 85b9124a73SGleb Smirnoff #endif 864cf49a43SJulian Elischer 874cf49a43SJulian Elischer /* List of commands */ 884cf49a43SJulian Elischer static const struct ngcmd *const cmds[] = { 897095e097SPoul-Henning Kamp &config_cmd, 904cf49a43SJulian Elischer &connect_cmd, 914cf49a43SJulian Elischer &debug_cmd, 92bbd6d60aSBrian Feldman &dot_cmd, 934cf49a43SJulian Elischer &help_cmd, 944cf49a43SJulian Elischer &list_cmd, 954cf49a43SJulian Elischer &mkpeer_cmd, 96f8307e12SArchie Cobbs &msg_cmd, 974cf49a43SJulian Elischer &name_cmd, 984cf49a43SJulian Elischer &read_cmd, 994cf49a43SJulian Elischer &rmhook_cmd, 1004cf49a43SJulian Elischer &show_cmd, 1014cf49a43SJulian Elischer &shutdown_cmd, 1024cf49a43SJulian Elischer &status_cmd, 1034cf49a43SJulian Elischer &types_cmd, 104be44fce4SArchie Cobbs &write_cmd, 1054cf49a43SJulian Elischer &quit_cmd, 1064cf49a43SJulian Elischer NULL 1074cf49a43SJulian Elischer }; 1084cf49a43SJulian Elischer 1094cf49a43SJulian Elischer /* Commands defined in this file */ 1104cf49a43SJulian Elischer const struct ngcmd read_cmd = { 1114cf49a43SJulian Elischer ReadCmd, 1124cf49a43SJulian Elischer "read <filename>", 1134cf49a43SJulian Elischer "Read and execute commands from a file", 114f8307e12SArchie Cobbs NULL, 115f8307e12SArchie Cobbs { "source", "." } 1164cf49a43SJulian Elischer }; 1174cf49a43SJulian Elischer const struct ngcmd help_cmd = { 1184cf49a43SJulian Elischer HelpCmd, 1194cf49a43SJulian Elischer "help [command]", 1204cf49a43SJulian Elischer "Show command summary or get more help on a specific command", 121f8307e12SArchie Cobbs NULL, 122f8307e12SArchie Cobbs { "?" } 1234cf49a43SJulian Elischer }; 1244cf49a43SJulian Elischer const struct ngcmd quit_cmd = { 1254cf49a43SJulian Elischer QuitCmd, 1264cf49a43SJulian Elischer "quit", 1274cf49a43SJulian Elischer "Exit program", 128f8307e12SArchie Cobbs NULL, 129f8307e12SArchie Cobbs { "exit" } 1304cf49a43SJulian Elischer }; 1314cf49a43SJulian Elischer 1324cf49a43SJulian Elischer /* Our control and data sockets */ 1334cf49a43SJulian Elischer int csock, dsock; 1344cf49a43SJulian Elischer 1354cf49a43SJulian Elischer /* 1364cf49a43SJulian Elischer * main() 1374cf49a43SJulian Elischer */ 1384cf49a43SJulian Elischer int 1394cf49a43SJulian Elischer main(int ac, char *av[]) 1404cf49a43SJulian Elischer { 1419d901d3bSHartmut Brandt char name[NG_NODESIZ]; 1424cf49a43SJulian Elischer int interactive = isatty(0) && isatty(1); 1434cf49a43SJulian Elischer FILE *fp = NULL; 144c44e20ebSMaxim Konovalov int ch, rtn = 0; 1454cf49a43SJulian Elischer 1464cf49a43SJulian Elischer /* Set default node name */ 1474cf49a43SJulian Elischer snprintf(name, sizeof(name), "ngctl%d", getpid()); 1484cf49a43SJulian Elischer 1494cf49a43SJulian Elischer /* Parse command line */ 1504cf49a43SJulian Elischer while ((ch = getopt(ac, av, "df:n:")) != EOF) { 1514cf49a43SJulian Elischer switch (ch) { 1524cf49a43SJulian Elischer case 'd': 1534cf49a43SJulian Elischer NgSetDebug(NgSetDebug(-1) + 1); 1544cf49a43SJulian Elischer break; 1554cf49a43SJulian Elischer case 'f': 1564cf49a43SJulian Elischer if (strcmp(optarg, "-") == 0) 1574cf49a43SJulian Elischer fp = stdin; 1584cf49a43SJulian Elischer else if ((fp = fopen(optarg, "r")) == NULL) 1594cf49a43SJulian Elischer err(EX_NOINPUT, "%s", optarg); 1604cf49a43SJulian Elischer break; 1614cf49a43SJulian Elischer case 'n': 1624cf49a43SJulian Elischer snprintf(name, sizeof(name), "%s", optarg); 1634cf49a43SJulian Elischer break; 1644cf49a43SJulian Elischer case '?': 1654cf49a43SJulian Elischer default: 1664cf49a43SJulian Elischer Usage((char *)NULL); 1674cf49a43SJulian Elischer break; 1684cf49a43SJulian Elischer } 1694cf49a43SJulian Elischer } 1704cf49a43SJulian Elischer ac -= optind; 1714cf49a43SJulian Elischer av += optind; 1724cf49a43SJulian Elischer 1734cf49a43SJulian Elischer /* Create a new socket node */ 174b08b2814SArchie Cobbs if (NgMkSockNode(name, &csock, &dsock) < 0) 1754cf49a43SJulian Elischer err(EX_OSERR, "can't create node"); 176c44e20ebSMaxim Konovalov 1774cf49a43SJulian Elischer /* Do commands as requested */ 1784cf49a43SJulian Elischer if (ac == 0) { 1794cf49a43SJulian Elischer if (fp != NULL) { 1804cf49a43SJulian Elischer rtn = ReadFile(fp); 1814cf49a43SJulian Elischer } else if (interactive) { 1824cf49a43SJulian Elischer rtn = DoInteractive(); 1834cf49a43SJulian Elischer } else 1844cf49a43SJulian Elischer Usage("no command specified"); 1854cf49a43SJulian Elischer } else { 1864cf49a43SJulian Elischer rtn = DoCommand(ac, av); 1874cf49a43SJulian Elischer } 1884cf49a43SJulian Elischer 1894cf49a43SJulian Elischer /* Convert command return code into system exit code */ 1904cf49a43SJulian Elischer switch (rtn) { 1914cf49a43SJulian Elischer case CMDRTN_OK: 1924cf49a43SJulian Elischer case CMDRTN_QUIT: 1934cf49a43SJulian Elischer rtn = 0; 1944cf49a43SJulian Elischer break; 1954cf49a43SJulian Elischer case CMDRTN_USAGE: 1964cf49a43SJulian Elischer rtn = EX_USAGE; 1974cf49a43SJulian Elischer break; 1984cf49a43SJulian Elischer case CMDRTN_ERROR: 1994cf49a43SJulian Elischer rtn = EX_OSERR; 2004cf49a43SJulian Elischer break; 2014cf49a43SJulian Elischer } 2024cf49a43SJulian Elischer return (rtn); 2034cf49a43SJulian Elischer } 2044cf49a43SJulian Elischer 2054cf49a43SJulian Elischer /* 2064cf49a43SJulian Elischer * Process commands from a file 2074cf49a43SJulian Elischer */ 2084cf49a43SJulian Elischer static int 2094cf49a43SJulian Elischer ReadFile(FILE *fp) 2104cf49a43SJulian Elischer { 2114cf49a43SJulian Elischer char line[LINE_MAX]; 2124cf49a43SJulian Elischer int num, rtn; 2134cf49a43SJulian Elischer 2144cf49a43SJulian Elischer for (num = 1; fgets(line, sizeof(line), fp) != NULL; num++) { 2154cf49a43SJulian Elischer if (*line == '#') 2164cf49a43SJulian Elischer continue; 2174cf49a43SJulian Elischer if ((rtn = DoParseCommand(line)) != 0) { 2184cf49a43SJulian Elischer warnx("line %d: error in file", num); 2194cf49a43SJulian Elischer return (rtn); 2204cf49a43SJulian Elischer } 2214cf49a43SJulian Elischer } 2224cf49a43SJulian Elischer return (CMDRTN_OK); 2234cf49a43SJulian Elischer } 2244cf49a43SJulian Elischer 225b9124a73SGleb Smirnoff #ifdef EDITLINE 226b9124a73SGleb Smirnoff /* Signal handler for Monitor() thread. */ 227b9124a73SGleb Smirnoff static void 228b9124a73SGleb Smirnoff Unblock(int signal) 229b9124a73SGleb Smirnoff { 230b9124a73SGleb Smirnoff unblock = 1; 231b9124a73SGleb Smirnoff } 232b9124a73SGleb Smirnoff 2334cf49a43SJulian Elischer /* 234b9124a73SGleb Smirnoff * Thread that monitors csock and dsock while main thread 235b9124a73SGleb Smirnoff * can be blocked in el_gets(). 236b9124a73SGleb Smirnoff */ 237b9124a73SGleb Smirnoff static void * 238b9124a73SGleb Smirnoff Monitor(void *v) 239b9124a73SGleb Smirnoff { 240b9124a73SGleb Smirnoff struct sigaction act; 241b9124a73SGleb Smirnoff const int maxfd = MAX(csock, dsock) + 1; 242b9124a73SGleb Smirnoff 243b9124a73SGleb Smirnoff act.sa_handler = Unblock; 244b9124a73SGleb Smirnoff sigemptyset(&act.sa_mask); 245b9124a73SGleb Smirnoff act.sa_flags = 0; 246b9124a73SGleb Smirnoff sigaction(SIGUSR1, &act, NULL); 247b9124a73SGleb Smirnoff 248b9124a73SGleb Smirnoff pthread_mutex_lock(&mutex); 249b9124a73SGleb Smirnoff for (;;) { 250b9124a73SGleb Smirnoff fd_set rfds; 251b9124a73SGleb Smirnoff 252b9124a73SGleb Smirnoff /* See if any data or control messages are arriving. */ 253b9124a73SGleb Smirnoff FD_ZERO(&rfds); 254b9124a73SGleb Smirnoff FD_SET(csock, &rfds); 255b9124a73SGleb Smirnoff FD_SET(dsock, &rfds); 256b9124a73SGleb Smirnoff unblock = 0; 257b9124a73SGleb Smirnoff if (select(maxfd, &rfds, NULL, NULL, NULL) <= 0) { 258b9124a73SGleb Smirnoff if (errno == EINTR) { 259b9124a73SGleb Smirnoff if (unblock == 1) 260b9124a73SGleb Smirnoff pthread_cond_wait(&cond, &mutex); 261b9124a73SGleb Smirnoff continue; 262b9124a73SGleb Smirnoff } 263b9124a73SGleb Smirnoff err(EX_OSERR, "select"); 264b9124a73SGleb Smirnoff } 265b9124a73SGleb Smirnoff 266b9124a73SGleb Smirnoff ReadSockets(rfds); 267b9124a73SGleb Smirnoff } 268b9124a73SGleb Smirnoff 269b9124a73SGleb Smirnoff return (NULL); 270b9124a73SGleb Smirnoff } 271b9124a73SGleb Smirnoff 272b9124a73SGleb Smirnoff static char * 273b9124a73SGleb Smirnoff Prompt(EditLine *el) 274b9124a73SGleb Smirnoff { 275b9124a73SGleb Smirnoff return PROMPT; 276b9124a73SGleb Smirnoff } 277b9124a73SGleb Smirnoff 278b9124a73SGleb Smirnoff /* 279b9124a73SGleb Smirnoff * Here we start a thread, that will monitor the netgraph 280b9124a73SGleb Smirnoff * sockets and catch any unexpected messages or data on them, 281b9124a73SGleb Smirnoff * that can arrive while user edits his/her commands. 282b9124a73SGleb Smirnoff * 283b9124a73SGleb Smirnoff * Whenever we expect data on netgraph sockets, we send signal 284b9124a73SGleb Smirnoff * to monitoring thread. The signal forces it to exit select() 285b9124a73SGleb Smirnoff * system call and sleep on condvar until we wake it. While 286b9124a73SGleb Smirnoff * monitoring thread sleeps, we can do our work with netgraph 287b9124a73SGleb Smirnoff * sockets. 288b9124a73SGleb Smirnoff */ 289b9124a73SGleb Smirnoff static int 290b9124a73SGleb Smirnoff DoInteractive(void) 291b9124a73SGleb Smirnoff { 292b9124a73SGleb Smirnoff pthread_t monitor; 293b9124a73SGleb Smirnoff EditLine *el; 294b9124a73SGleb Smirnoff History *hist; 295b9124a73SGleb Smirnoff HistEvent hev = { 0, "" }; 296b9124a73SGleb Smirnoff 297b9124a73SGleb Smirnoff (*help_cmd.func)(0, NULL); 298b9124a73SGleb Smirnoff pthread_create(&monitor, NULL, Monitor, NULL); 299b9124a73SGleb Smirnoff el = el_init(getprogname(), stdin, stdout, stderr); 300b9124a73SGleb Smirnoff if (el == NULL) 301b9124a73SGleb Smirnoff return (CMDRTN_ERROR); 302b9124a73SGleb Smirnoff el_set(el, EL_PROMPT, Prompt); 303b9124a73SGleb Smirnoff el_set(el, EL_SIGNAL, 1); 304b9124a73SGleb Smirnoff el_set(el, EL_EDITOR, "emacs"); 305b9124a73SGleb Smirnoff hist = history_init(); 306b9124a73SGleb Smirnoff if (hist == NULL) 307b9124a73SGleb Smirnoff return (CMDRTN_ERROR); 308b9124a73SGleb Smirnoff history(hist, &hev, H_SETSIZE, 100); 309b9124a73SGleb Smirnoff history(hist, &hev, H_SETUNIQUE, 1); 310b9124a73SGleb Smirnoff el_set(el, EL_HIST, history, (const char *)hist); 311b9124a73SGleb Smirnoff el_source(el, NULL); 312b9124a73SGleb Smirnoff 313b9124a73SGleb Smirnoff for (;;) { 314b9124a73SGleb Smirnoff const char *buf; 315b9124a73SGleb Smirnoff int count; 316b9124a73SGleb Smirnoff 317b9124a73SGleb Smirnoff if ((buf = el_gets(el, &count)) == NULL) { 318b9124a73SGleb Smirnoff printf("\n"); 319b9124a73SGleb Smirnoff break; 320b9124a73SGleb Smirnoff } 321b9124a73SGleb Smirnoff history(hist, &hev, H_ENTER, buf); 322b9124a73SGleb Smirnoff pthread_kill(monitor, SIGUSR1); 323b9124a73SGleb Smirnoff pthread_mutex_lock(&mutex); 324b9124a73SGleb Smirnoff if (DoParseCommand((char *)buf) == CMDRTN_QUIT) 325b9124a73SGleb Smirnoff break; 326b9124a73SGleb Smirnoff pthread_cond_signal(&cond); 327b9124a73SGleb Smirnoff pthread_mutex_unlock(&mutex); 328b9124a73SGleb Smirnoff } 329b9124a73SGleb Smirnoff 330b9124a73SGleb Smirnoff history_end(hist); 331b9124a73SGleb Smirnoff el_end(el); 332b9124a73SGleb Smirnoff pthread_cancel(monitor); 333b9124a73SGleb Smirnoff 334b9124a73SGleb Smirnoff return (CMDRTN_QUIT); 335b9124a73SGleb Smirnoff } 336b9124a73SGleb Smirnoff 337b9124a73SGleb Smirnoff #else /* !EDITLINE */ 338b9124a73SGleb Smirnoff 339b9124a73SGleb Smirnoff /* 340b9124a73SGleb Smirnoff * Interactive mode w/o libedit functionality. 3414cf49a43SJulian Elischer */ 3424cf49a43SJulian Elischer static int 3434cf49a43SJulian Elischer DoInteractive(void) 3444cf49a43SJulian Elischer { 345f8307e12SArchie Cobbs const int maxfd = MAX(csock, dsock) + 1; 346f8307e12SArchie Cobbs 347f8307e12SArchie Cobbs (*help_cmd.func)(0, NULL); 348f8307e12SArchie Cobbs while (1) { 349f8307e12SArchie Cobbs struct timeval tv; 350f8307e12SArchie Cobbs fd_set rfds; 351f8307e12SArchie Cobbs 352f8307e12SArchie Cobbs /* See if any data or control messages are arriving */ 353f8307e12SArchie Cobbs FD_ZERO(&rfds); 354f8307e12SArchie Cobbs FD_SET(csock, &rfds); 355f8307e12SArchie Cobbs FD_SET(dsock, &rfds); 356f8307e12SArchie Cobbs memset(&tv, 0, sizeof(tv)); 357f8307e12SArchie Cobbs if (select(maxfd, &rfds, NULL, NULL, &tv) <= 0) { 358f8307e12SArchie Cobbs 359f8307e12SArchie Cobbs /* Issue prompt and wait for anything to happen */ 360f8307e12SArchie Cobbs printf("%s", PROMPT); 361f8307e12SArchie Cobbs fflush(stdout); 362f8307e12SArchie Cobbs FD_ZERO(&rfds); 363f8307e12SArchie Cobbs FD_SET(0, &rfds); 364f8307e12SArchie Cobbs FD_SET(csock, &rfds); 365f8307e12SArchie Cobbs FD_SET(dsock, &rfds); 366f8307e12SArchie Cobbs if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) 367f8307e12SArchie Cobbs err(EX_OSERR, "select"); 368f8307e12SArchie Cobbs 369f8307e12SArchie Cobbs /* If not user input, print a newline first */ 370f8307e12SArchie Cobbs if (!FD_ISSET(0, &rfds)) 371f8307e12SArchie Cobbs printf("\n"); 372f8307e12SArchie Cobbs } 373f8307e12SArchie Cobbs 374b9124a73SGleb Smirnoff ReadSockets(rfds); 375f8307e12SArchie Cobbs 376f8307e12SArchie Cobbs /* Get any user input */ 377f8307e12SArchie Cobbs if (FD_ISSET(0, &rfds)) { 3780c5c7719SPoul-Henning Kamp char buf[LINE_MAX]; 3790c5c7719SPoul-Henning Kamp 3800c5c7719SPoul-Henning Kamp if (fgets(buf, sizeof(buf), stdin) == NULL) { 3810c5c7719SPoul-Henning Kamp printf("\n"); 3820c5c7719SPoul-Henning Kamp break; 3830c5c7719SPoul-Henning Kamp } 3840c5c7719SPoul-Henning Kamp if (DoParseCommand(buf) == CMDRTN_QUIT) 385f8307e12SArchie Cobbs break; 386f8307e12SArchie Cobbs } 387f8307e12SArchie Cobbs } 3884cf49a43SJulian Elischer return (CMDRTN_QUIT); 3894cf49a43SJulian Elischer } 390b9124a73SGleb Smirnoff #endif /* !EDITLINE */ 391b9124a73SGleb Smirnoff 392b9124a73SGleb Smirnoff /* 393b9124a73SGleb Smirnoff * Read and process data on netgraph control and data sockets. 394b9124a73SGleb Smirnoff */ 395b9124a73SGleb Smirnoff static void 396b9124a73SGleb Smirnoff ReadSockets(fd_set rfds) 397b9124a73SGleb Smirnoff { 398b9124a73SGleb Smirnoff /* Display any incoming control message. */ 399b9124a73SGleb Smirnoff if (FD_ISSET(csock, &rfds)) 400b9124a73SGleb Smirnoff MsgRead(); 401b9124a73SGleb Smirnoff 402b9124a73SGleb Smirnoff /* Display any incoming data packet. */ 403b9124a73SGleb Smirnoff if (FD_ISSET(dsock, &rfds)) { 404b9124a73SGleb Smirnoff char hook[NG_HOOKSIZ]; 405b9124a73SGleb Smirnoff u_char *buf; 406b9124a73SGleb Smirnoff int rl; 407b9124a73SGleb Smirnoff 408b9124a73SGleb Smirnoff /* Read packet from socket. */ 409b9124a73SGleb Smirnoff if ((rl = NgAllocRecvData(dsock, &buf, hook)) < 0) 410b9124a73SGleb Smirnoff err(EX_OSERR, "reading hook \"%s\"", hook); 411b9124a73SGleb Smirnoff if (rl == 0) 412b9124a73SGleb Smirnoff errx(EX_OSERR, "EOF from hook \"%s\"?", hook); 413b9124a73SGleb Smirnoff 414b9124a73SGleb Smirnoff /* Write packet to stdout. */ 415b9124a73SGleb Smirnoff printf("Rec'd data packet on hook \"%s\":\n", hook); 416b9124a73SGleb Smirnoff DumpAscii(buf, rl); 417b9124a73SGleb Smirnoff free(buf); 418b9124a73SGleb Smirnoff } 419b9124a73SGleb Smirnoff } 4204cf49a43SJulian Elischer 4214cf49a43SJulian Elischer /* 4224cf49a43SJulian Elischer * Parse a command line and execute the command 4234cf49a43SJulian Elischer */ 4244cf49a43SJulian Elischer static int 4254cf49a43SJulian Elischer DoParseCommand(char *line) 4264cf49a43SJulian Elischer { 4274cf49a43SJulian Elischer char *av[MAX_ARGS]; 4284cf49a43SJulian Elischer int ac; 4294cf49a43SJulian Elischer 4304cf49a43SJulian Elischer /* Parse line */ 4314cf49a43SJulian Elischer for (ac = 0, av[0] = strtok(line, WHITESPACE); 4324cf49a43SJulian Elischer ac < MAX_ARGS - 1 && av[ac]; 4334cf49a43SJulian Elischer av[++ac] = strtok(NULL, WHITESPACE)); 4344cf49a43SJulian Elischer 4354cf49a43SJulian Elischer /* Do command */ 4364cf49a43SJulian Elischer return (DoCommand(ac, av)); 4374cf49a43SJulian Elischer } 4384cf49a43SJulian Elischer 4394cf49a43SJulian Elischer /* 4404cf49a43SJulian Elischer * Execute the command 4414cf49a43SJulian Elischer */ 4424cf49a43SJulian Elischer static int 4434cf49a43SJulian Elischer DoCommand(int ac, char **av) 4444cf49a43SJulian Elischer { 4454cf49a43SJulian Elischer const struct ngcmd *cmd; 4464cf49a43SJulian Elischer int rtn; 4474cf49a43SJulian Elischer 4484cf49a43SJulian Elischer if (ac == 0 || *av[0] == 0) 4494cf49a43SJulian Elischer return (CMDRTN_OK); 4504cf49a43SJulian Elischer if ((cmd = FindCommand(av[0])) == NULL) 4514cf49a43SJulian Elischer return (CMDRTN_ERROR); 4524cf49a43SJulian Elischer if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE) 4534cf49a43SJulian Elischer warnx("usage: %s", cmd->cmd); 4544cf49a43SJulian Elischer return (rtn); 4554cf49a43SJulian Elischer } 4564cf49a43SJulian Elischer 4574cf49a43SJulian Elischer /* 4584cf49a43SJulian Elischer * Find a command 4594cf49a43SJulian Elischer */ 4604cf49a43SJulian Elischer static const struct ngcmd * 4614cf49a43SJulian Elischer FindCommand(const char *string) 4624cf49a43SJulian Elischer { 463f8307e12SArchie Cobbs int k, found = -1; 4644cf49a43SJulian Elischer 465f8307e12SArchie Cobbs for (k = 0; cmds[k] != NULL; k++) { 466f8307e12SArchie Cobbs if (MatchCommand(cmds[k], string)) { 4674cf49a43SJulian Elischer if (found != -1) { 4684cf49a43SJulian Elischer warnx("\"%s\": ambiguous command", string); 4694cf49a43SJulian Elischer return (NULL); 4704cf49a43SJulian Elischer } 4714cf49a43SJulian Elischer found = k; 4724cf49a43SJulian Elischer } 4734cf49a43SJulian Elischer } 4744cf49a43SJulian Elischer if (found == -1) { 4754cf49a43SJulian Elischer warnx("\"%s\": unknown command", string); 4764cf49a43SJulian Elischer return (NULL); 4774cf49a43SJulian Elischer } 4784cf49a43SJulian Elischer return (cmds[found]); 4794cf49a43SJulian Elischer } 4804cf49a43SJulian Elischer 4814cf49a43SJulian Elischer /* 482f8307e12SArchie Cobbs * See if string matches a prefix of "cmd" (or an alias) case insensitively 483f8307e12SArchie Cobbs */ 484f8307e12SArchie Cobbs static int 485f8307e12SArchie Cobbs MatchCommand(const struct ngcmd *cmd, const char *s) 486f8307e12SArchie Cobbs { 487f8307e12SArchie Cobbs int a; 488f8307e12SArchie Cobbs 489f8307e12SArchie Cobbs /* Try to match command, ignoring the usage stuff */ 490f8307e12SArchie Cobbs if (strlen(s) <= strcspn(cmd->cmd, WHITESPACE)) { 491f8307e12SArchie Cobbs if (strncasecmp(s, cmd->cmd, strlen(s)) == 0) 492f8307e12SArchie Cobbs return (1); 493f8307e12SArchie Cobbs } 494f8307e12SArchie Cobbs 495f8307e12SArchie Cobbs /* Try to match aliases */ 496f8307e12SArchie Cobbs for (a = 0; a < MAX_CMD_ALIAS && cmd->aliases[a] != NULL; a++) { 497f8307e12SArchie Cobbs if (strlen(cmd->aliases[a]) >= strlen(s)) { 498f8307e12SArchie Cobbs if (strncasecmp(s, cmd->aliases[a], strlen(s)) == 0) 499f8307e12SArchie Cobbs return (1); 500f8307e12SArchie Cobbs } 501f8307e12SArchie Cobbs } 502f8307e12SArchie Cobbs 503f8307e12SArchie Cobbs /* No match */ 504f8307e12SArchie Cobbs return (0); 505f8307e12SArchie Cobbs } 506f8307e12SArchie Cobbs 507f8307e12SArchie Cobbs /* 5084cf49a43SJulian Elischer * ReadCmd() 5094cf49a43SJulian Elischer */ 5104cf49a43SJulian Elischer static int 5114cf49a43SJulian Elischer ReadCmd(int ac, char **av) 5124cf49a43SJulian Elischer { 5134cf49a43SJulian Elischer FILE *fp; 5144cf49a43SJulian Elischer int rtn; 5154cf49a43SJulian Elischer 5164cf49a43SJulian Elischer /* Open file */ 5174cf49a43SJulian Elischer switch (ac) { 5184cf49a43SJulian Elischer case 2: 519f35e82dfSArchie Cobbs if ((fp = fopen(av[1], "r")) == NULL) { 5204cf49a43SJulian Elischer warn("%s", av[1]); 5214cf49a43SJulian Elischer return (CMDRTN_ERROR); 522f35e82dfSArchie Cobbs } 523f35e82dfSArchie Cobbs break; 5244cf49a43SJulian Elischer default: 5254cf49a43SJulian Elischer return (CMDRTN_USAGE); 5264cf49a43SJulian Elischer } 5274cf49a43SJulian Elischer 5284cf49a43SJulian Elischer /* Process it */ 5294cf49a43SJulian Elischer rtn = ReadFile(fp); 5304cf49a43SJulian Elischer fclose(fp); 5314cf49a43SJulian Elischer return (rtn); 5324cf49a43SJulian Elischer } 5334cf49a43SJulian Elischer 5344cf49a43SJulian Elischer /* 5354cf49a43SJulian Elischer * HelpCmd() 5364cf49a43SJulian Elischer */ 5374cf49a43SJulian Elischer static int 5384cf49a43SJulian Elischer HelpCmd(int ac, char **av) 5394cf49a43SJulian Elischer { 5404cf49a43SJulian Elischer const struct ngcmd *cmd; 5414cf49a43SJulian Elischer int k; 5424cf49a43SJulian Elischer 5434cf49a43SJulian Elischer switch (ac) { 5444cf49a43SJulian Elischer case 0: 5454cf49a43SJulian Elischer case 1: 5464cf49a43SJulian Elischer /* Show all commands */ 5474cf49a43SJulian Elischer printf("Available commands:\n"); 5484cf49a43SJulian Elischer for (k = 0; cmds[k] != NULL; k++) { 5494cf49a43SJulian Elischer char *s, buf[100]; 5504cf49a43SJulian Elischer 5514cf49a43SJulian Elischer cmd = cmds[k]; 5524cf49a43SJulian Elischer snprintf(buf, sizeof(buf), "%s", cmd->cmd); 5534cf49a43SJulian Elischer for (s = buf; *s != '\0' && !isspace(*s); s++); 5544cf49a43SJulian Elischer *s = '\0'; 5554cf49a43SJulian Elischer printf(" %-10s %s\n", buf, cmd->desc); 5564cf49a43SJulian Elischer } 5574cf49a43SJulian Elischer return (CMDRTN_OK); 5584cf49a43SJulian Elischer default: 5594cf49a43SJulian Elischer /* Show help on a specific command */ 5604cf49a43SJulian Elischer if ((cmd = FindCommand(av[1])) != NULL) { 561d3974088SDag-Erling Smørgrav printf("usage: %s\n", cmd->cmd); 562f8307e12SArchie Cobbs if (cmd->aliases[0] != NULL) { 563f8307e12SArchie Cobbs int a = 0; 564f8307e12SArchie Cobbs 565f8307e12SArchie Cobbs printf("Aliases: "); 566f8307e12SArchie Cobbs while (1) { 567f8307e12SArchie Cobbs printf("%s", cmd->aliases[a++]); 568f8307e12SArchie Cobbs if (a == MAX_CMD_ALIAS 569f8307e12SArchie Cobbs || cmd->aliases[a] == NULL) { 570f8307e12SArchie Cobbs printf("\n"); 571f8307e12SArchie Cobbs break; 572f8307e12SArchie Cobbs } 573f8307e12SArchie Cobbs printf(", "); 574f8307e12SArchie Cobbs } 575f8307e12SArchie Cobbs } 5764cf49a43SJulian Elischer printf("Summary: %s\n", cmd->desc); 5774cf49a43SJulian Elischer if (cmd->help != NULL) { 5784cf49a43SJulian Elischer const char *s; 5794cf49a43SJulian Elischer char buf[65]; 5804cf49a43SJulian Elischer int tot, len, done; 5814cf49a43SJulian Elischer 5824cf49a43SJulian Elischer printf("Description:\n"); 5834cf49a43SJulian Elischer for (s = cmd->help; *s != '\0'; s += len) { 5844cf49a43SJulian Elischer while (isspace(*s)) 5854cf49a43SJulian Elischer s++; 5864cf49a43SJulian Elischer tot = snprintf(buf, 5874cf49a43SJulian Elischer sizeof(buf), "%s", s); 5884cf49a43SJulian Elischer len = strlen(buf); 5894cf49a43SJulian Elischer done = len == tot; 5904cf49a43SJulian Elischer if (!done) { 5914cf49a43SJulian Elischer while (len > 0 5924cf49a43SJulian Elischer && !isspace(buf[len-1])) 5934cf49a43SJulian Elischer buf[--len] = '\0'; 5944cf49a43SJulian Elischer } 5954cf49a43SJulian Elischer printf(" %s\n", buf); 5964cf49a43SJulian Elischer } 5974cf49a43SJulian Elischer } 5984cf49a43SJulian Elischer } 5994cf49a43SJulian Elischer } 6004cf49a43SJulian Elischer return (CMDRTN_OK); 6014cf49a43SJulian Elischer } 6024cf49a43SJulian Elischer 6034cf49a43SJulian Elischer /* 6044cf49a43SJulian Elischer * QuitCmd() 6054cf49a43SJulian Elischer */ 6064cf49a43SJulian Elischer static int 607723c1c2eSRuslan Ermilov QuitCmd(int ac __unused, char **av __unused) 6084cf49a43SJulian Elischer { 6094cf49a43SJulian Elischer return (CMDRTN_QUIT); 6104cf49a43SJulian Elischer } 6114cf49a43SJulian Elischer 6124cf49a43SJulian Elischer /* 613f8307e12SArchie Cobbs * Dump data in hex and ASCII form 614f8307e12SArchie Cobbs */ 6156ebb8ebbSArchie Cobbs void 616f8307e12SArchie Cobbs DumpAscii(const u_char *buf, int len) 617f8307e12SArchie Cobbs { 618f8307e12SArchie Cobbs char ch, sbuf[100]; 619f8307e12SArchie Cobbs int k, count; 620f8307e12SArchie Cobbs 621f8307e12SArchie Cobbs for (count = 0; count < len; count += DUMP_BYTES_PER_LINE) { 622f8307e12SArchie Cobbs snprintf(sbuf, sizeof(sbuf), "%04x: ", count); 623f8307e12SArchie Cobbs for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 624f8307e12SArchie Cobbs if (count + k < len) { 625f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), 626f8307e12SArchie Cobbs sizeof(sbuf) - strlen(sbuf), 627f8307e12SArchie Cobbs "%02x ", buf[count + k]); 628f8307e12SArchie Cobbs } else { 629f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), 630f8307e12SArchie Cobbs sizeof(sbuf) - strlen(sbuf), " "); 631f8307e12SArchie Cobbs } 632f8307e12SArchie Cobbs } 633f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " "); 634f8307e12SArchie Cobbs for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 635f8307e12SArchie Cobbs if (count + k < len) { 636f8307e12SArchie Cobbs ch = isprint(buf[count + k]) ? 637f8307e12SArchie Cobbs buf[count + k] : '.'; 638f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), 639f8307e12SArchie Cobbs sizeof(sbuf) - strlen(sbuf), "%c", ch); 640f8307e12SArchie Cobbs } else { 641f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), 642f8307e12SArchie Cobbs sizeof(sbuf) - strlen(sbuf), " "); 643f8307e12SArchie Cobbs } 644f8307e12SArchie Cobbs } 645f8307e12SArchie Cobbs printf("%s\n", sbuf); 646f8307e12SArchie Cobbs } 647f8307e12SArchie Cobbs } 648f8307e12SArchie Cobbs 649f8307e12SArchie Cobbs /* 6504cf49a43SJulian Elischer * Usage() 6514cf49a43SJulian Elischer */ 6524cf49a43SJulian Elischer static void 6534cf49a43SJulian Elischer Usage(const char *msg) 6544cf49a43SJulian Elischer { 6554cf49a43SJulian Elischer if (msg) 6564cf49a43SJulian Elischer warnx("%s", msg); 657b00304d4SPhilippe Charnier fprintf(stderr, 658b00304d4SPhilippe Charnier "usage: ngctl [-d] [-f file] [-n name] [command ...]\n"); 659b00304d4SPhilippe Charnier exit(EX_USAGE); 6604cf49a43SJulian Elischer } 661