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); 71eac2afceSGleb 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 */ 1509c20ad30SKevin Lo while ((ch = getopt(ac, av, "df:n:")) != -1) { 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 { 230eac2afceSGleb Smirnoff 231b9124a73SGleb Smirnoff unblock = 1; 232b9124a73SGleb Smirnoff } 233b9124a73SGleb Smirnoff 2344cf49a43SJulian Elischer /* 235b9124a73SGleb Smirnoff * Thread that monitors csock and dsock while main thread 236b9124a73SGleb Smirnoff * can be blocked in el_gets(). 237b9124a73SGleb Smirnoff */ 238b9124a73SGleb Smirnoff static void * 239b9124a73SGleb Smirnoff Monitor(void *v) 240b9124a73SGleb Smirnoff { 241b9124a73SGleb Smirnoff struct sigaction act; 242b9124a73SGleb Smirnoff const int maxfd = MAX(csock, dsock) + 1; 243b9124a73SGleb Smirnoff 244b9124a73SGleb Smirnoff act.sa_handler = Unblock; 245b9124a73SGleb Smirnoff sigemptyset(&act.sa_mask); 246b9124a73SGleb Smirnoff act.sa_flags = 0; 247b9124a73SGleb Smirnoff sigaction(SIGUSR1, &act, NULL); 248b9124a73SGleb Smirnoff 249b9124a73SGleb Smirnoff pthread_mutex_lock(&mutex); 250b9124a73SGleb Smirnoff for (;;) { 251b9124a73SGleb Smirnoff fd_set rfds; 252b9124a73SGleb Smirnoff 253b9124a73SGleb Smirnoff /* See if any data or control messages are arriving. */ 254b9124a73SGleb Smirnoff FD_ZERO(&rfds); 255b9124a73SGleb Smirnoff FD_SET(csock, &rfds); 256b9124a73SGleb Smirnoff FD_SET(dsock, &rfds); 257b9124a73SGleb Smirnoff unblock = 0; 258b9124a73SGleb Smirnoff if (select(maxfd, &rfds, NULL, NULL, NULL) <= 0) { 259b9124a73SGleb Smirnoff if (errno == EINTR) { 260b9124a73SGleb Smirnoff if (unblock == 1) 261b9124a73SGleb Smirnoff pthread_cond_wait(&cond, &mutex); 262b9124a73SGleb Smirnoff continue; 263b9124a73SGleb Smirnoff } 264b9124a73SGleb Smirnoff err(EX_OSERR, "select"); 265b9124a73SGleb Smirnoff } 266eac2afceSGleb 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 { 275eac2afceSGleb Smirnoff 276eac2afceSGleb Smirnoff return (PROMPT); 277b9124a73SGleb Smirnoff } 278b9124a73SGleb Smirnoff 279b9124a73SGleb Smirnoff /* 280b9124a73SGleb Smirnoff * Here we start a thread, that will monitor the netgraph 281b9124a73SGleb Smirnoff * sockets and catch any unexpected messages or data on them, 282b9124a73SGleb Smirnoff * that can arrive while user edits his/her commands. 283b9124a73SGleb Smirnoff * 284b9124a73SGleb Smirnoff * Whenever we expect data on netgraph sockets, we send signal 285b9124a73SGleb Smirnoff * to monitoring thread. The signal forces it to exit select() 286b9124a73SGleb Smirnoff * system call and sleep on condvar until we wake it. While 287b9124a73SGleb Smirnoff * monitoring thread sleeps, we can do our work with netgraph 288b9124a73SGleb Smirnoff * sockets. 289b9124a73SGleb Smirnoff */ 290b9124a73SGleb Smirnoff static int 291b9124a73SGleb Smirnoff DoInteractive(void) 292b9124a73SGleb Smirnoff { 293b9124a73SGleb Smirnoff pthread_t monitor; 294b9124a73SGleb Smirnoff EditLine *el; 295b9124a73SGleb Smirnoff History *hist; 296b9124a73SGleb Smirnoff HistEvent hev = { 0, "" }; 297b9124a73SGleb Smirnoff 298b9124a73SGleb Smirnoff (*help_cmd.func)(0, NULL); 299b9124a73SGleb Smirnoff pthread_create(&monitor, NULL, Monitor, NULL); 300b9124a73SGleb Smirnoff el = el_init(getprogname(), stdin, stdout, stderr); 301b9124a73SGleb Smirnoff if (el == NULL) 302b9124a73SGleb Smirnoff return (CMDRTN_ERROR); 303b9124a73SGleb Smirnoff el_set(el, EL_PROMPT, Prompt); 304b9124a73SGleb Smirnoff el_set(el, EL_SIGNAL, 1); 305b9124a73SGleb Smirnoff el_set(el, EL_EDITOR, "emacs"); 306b9124a73SGleb Smirnoff hist = history_init(); 307b9124a73SGleb Smirnoff if (hist == NULL) 308b9124a73SGleb Smirnoff return (CMDRTN_ERROR); 309b9124a73SGleb Smirnoff history(hist, &hev, H_SETSIZE, 100); 310b9124a73SGleb Smirnoff history(hist, &hev, H_SETUNIQUE, 1); 311b9124a73SGleb Smirnoff el_set(el, EL_HIST, history, (const char *)hist); 312b9124a73SGleb Smirnoff el_source(el, NULL); 313b9124a73SGleb Smirnoff 314b9124a73SGleb Smirnoff for (;;) { 315b9124a73SGleb Smirnoff const char *buf; 316b9124a73SGleb Smirnoff int count; 317b9124a73SGleb Smirnoff 318b9124a73SGleb Smirnoff if ((buf = el_gets(el, &count)) == NULL) { 319b9124a73SGleb Smirnoff printf("\n"); 320b9124a73SGleb Smirnoff break; 321b9124a73SGleb Smirnoff } 322b9124a73SGleb Smirnoff history(hist, &hev, H_ENTER, buf); 323b9124a73SGleb Smirnoff pthread_kill(monitor, SIGUSR1); 324b9124a73SGleb Smirnoff pthread_mutex_lock(&mutex); 325b9124a73SGleb Smirnoff if (DoParseCommand((char *)buf) == CMDRTN_QUIT) 326b9124a73SGleb Smirnoff break; 327b9124a73SGleb Smirnoff pthread_cond_signal(&cond); 328b9124a73SGleb Smirnoff pthread_mutex_unlock(&mutex); 329b9124a73SGleb Smirnoff } 330b9124a73SGleb Smirnoff 331b9124a73SGleb Smirnoff history_end(hist); 332b9124a73SGleb Smirnoff el_end(el); 333b9124a73SGleb Smirnoff pthread_cancel(monitor); 334b9124a73SGleb Smirnoff 335b9124a73SGleb Smirnoff return (CMDRTN_QUIT); 336b9124a73SGleb Smirnoff } 337b9124a73SGleb Smirnoff 338b9124a73SGleb Smirnoff #else /* !EDITLINE */ 339b9124a73SGleb Smirnoff 340b9124a73SGleb Smirnoff /* 341b9124a73SGleb Smirnoff * Interactive mode w/o libedit functionality. 3424cf49a43SJulian Elischer */ 3434cf49a43SJulian Elischer static int 3444cf49a43SJulian Elischer DoInteractive(void) 3454cf49a43SJulian Elischer { 346f8307e12SArchie Cobbs const int maxfd = MAX(csock, dsock) + 1; 347f8307e12SArchie Cobbs 348f8307e12SArchie Cobbs (*help_cmd.func)(0, NULL); 349f8307e12SArchie Cobbs while (1) { 350f8307e12SArchie Cobbs struct timeval tv; 351f8307e12SArchie Cobbs fd_set rfds; 352f8307e12SArchie Cobbs 353f8307e12SArchie Cobbs /* See if any data or control messages are arriving */ 354f8307e12SArchie Cobbs FD_ZERO(&rfds); 355f8307e12SArchie Cobbs FD_SET(csock, &rfds); 356f8307e12SArchie Cobbs FD_SET(dsock, &rfds); 357f8307e12SArchie Cobbs memset(&tv, 0, sizeof(tv)); 358f8307e12SArchie Cobbs if (select(maxfd, &rfds, NULL, NULL, &tv) <= 0) { 359f8307e12SArchie Cobbs 360f8307e12SArchie Cobbs /* Issue prompt and wait for anything to happen */ 361f8307e12SArchie Cobbs printf("%s", PROMPT); 362f8307e12SArchie Cobbs fflush(stdout); 363f8307e12SArchie Cobbs FD_ZERO(&rfds); 364f8307e12SArchie Cobbs FD_SET(0, &rfds); 365f8307e12SArchie Cobbs FD_SET(csock, &rfds); 366f8307e12SArchie Cobbs FD_SET(dsock, &rfds); 367f8307e12SArchie Cobbs if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) 368f8307e12SArchie Cobbs err(EX_OSERR, "select"); 369f8307e12SArchie Cobbs 370f8307e12SArchie Cobbs /* If not user input, print a newline first */ 371f8307e12SArchie Cobbs if (!FD_ISSET(0, &rfds)) 372f8307e12SArchie Cobbs printf("\n"); 373f8307e12SArchie Cobbs } 374f8307e12SArchie Cobbs 375eac2afceSGleb Smirnoff ReadSockets(&rfds); 376f8307e12SArchie Cobbs 377f8307e12SArchie Cobbs /* Get any user input */ 378f8307e12SArchie Cobbs if (FD_ISSET(0, &rfds)) { 3790c5c7719SPoul-Henning Kamp char buf[LINE_MAX]; 3800c5c7719SPoul-Henning Kamp 3810c5c7719SPoul-Henning Kamp if (fgets(buf, sizeof(buf), stdin) == NULL) { 3820c5c7719SPoul-Henning Kamp printf("\n"); 3830c5c7719SPoul-Henning Kamp break; 3840c5c7719SPoul-Henning Kamp } 3850c5c7719SPoul-Henning Kamp if (DoParseCommand(buf) == CMDRTN_QUIT) 386f8307e12SArchie Cobbs break; 387f8307e12SArchie Cobbs } 388f8307e12SArchie Cobbs } 3894cf49a43SJulian Elischer return (CMDRTN_QUIT); 3904cf49a43SJulian Elischer } 391b9124a73SGleb Smirnoff #endif /* !EDITLINE */ 392b9124a73SGleb Smirnoff 393b9124a73SGleb Smirnoff /* 394b9124a73SGleb Smirnoff * Read and process data on netgraph control and data sockets. 395b9124a73SGleb Smirnoff */ 396b9124a73SGleb Smirnoff static void 397eac2afceSGleb Smirnoff ReadSockets(fd_set *rfds) 398b9124a73SGleb Smirnoff { 399b9124a73SGleb Smirnoff /* Display any incoming control message. */ 400eac2afceSGleb Smirnoff if (FD_ISSET(csock, rfds)) 401b9124a73SGleb Smirnoff MsgRead(); 402b9124a73SGleb Smirnoff 403b9124a73SGleb Smirnoff /* Display any incoming data packet. */ 404eac2afceSGleb Smirnoff if (FD_ISSET(dsock, rfds)) { 405b9124a73SGleb Smirnoff char hook[NG_HOOKSIZ]; 406b9124a73SGleb Smirnoff u_char *buf; 407b9124a73SGleb Smirnoff int rl; 408b9124a73SGleb Smirnoff 409b9124a73SGleb Smirnoff /* Read packet from socket. */ 410b9124a73SGleb Smirnoff if ((rl = NgAllocRecvData(dsock, &buf, hook)) < 0) 411b9124a73SGleb Smirnoff err(EX_OSERR, "reading hook \"%s\"", hook); 412b9124a73SGleb Smirnoff if (rl == 0) 413b9124a73SGleb Smirnoff errx(EX_OSERR, "EOF from hook \"%s\"?", hook); 414b9124a73SGleb Smirnoff 415b9124a73SGleb Smirnoff /* Write packet to stdout. */ 416b9124a73SGleb Smirnoff printf("Rec'd data packet on hook \"%s\":\n", hook); 417b9124a73SGleb Smirnoff DumpAscii(buf, rl); 418b9124a73SGleb Smirnoff free(buf); 419b9124a73SGleb Smirnoff } 420b9124a73SGleb Smirnoff } 4214cf49a43SJulian Elischer 4224cf49a43SJulian Elischer /* 4234cf49a43SJulian Elischer * Parse a command line and execute the command 4244cf49a43SJulian Elischer */ 4254cf49a43SJulian Elischer static int 4264cf49a43SJulian Elischer DoParseCommand(char *line) 4274cf49a43SJulian Elischer { 4284cf49a43SJulian Elischer char *av[MAX_ARGS]; 4294cf49a43SJulian Elischer int ac; 4304cf49a43SJulian Elischer 4314cf49a43SJulian Elischer /* Parse line */ 4324cf49a43SJulian Elischer for (ac = 0, av[0] = strtok(line, WHITESPACE); 4334cf49a43SJulian Elischer ac < MAX_ARGS - 1 && av[ac]; 4344cf49a43SJulian Elischer av[++ac] = strtok(NULL, WHITESPACE)); 4354cf49a43SJulian Elischer 4364cf49a43SJulian Elischer /* Do command */ 4374cf49a43SJulian Elischer return (DoCommand(ac, av)); 4384cf49a43SJulian Elischer } 4394cf49a43SJulian Elischer 4404cf49a43SJulian Elischer /* 4414cf49a43SJulian Elischer * Execute the command 4424cf49a43SJulian Elischer */ 4434cf49a43SJulian Elischer static int 4444cf49a43SJulian Elischer DoCommand(int ac, char **av) 4454cf49a43SJulian Elischer { 4464cf49a43SJulian Elischer const struct ngcmd *cmd; 4474cf49a43SJulian Elischer int rtn; 4484cf49a43SJulian Elischer 4494cf49a43SJulian Elischer if (ac == 0 || *av[0] == 0) 4504cf49a43SJulian Elischer return (CMDRTN_OK); 4514cf49a43SJulian Elischer if ((cmd = FindCommand(av[0])) == NULL) 4524cf49a43SJulian Elischer return (CMDRTN_ERROR); 4534cf49a43SJulian Elischer if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE) 4544cf49a43SJulian Elischer warnx("usage: %s", cmd->cmd); 4554cf49a43SJulian Elischer return (rtn); 4564cf49a43SJulian Elischer } 4574cf49a43SJulian Elischer 4584cf49a43SJulian Elischer /* 4594cf49a43SJulian Elischer * Find a command 4604cf49a43SJulian Elischer */ 4614cf49a43SJulian Elischer static const struct ngcmd * 4624cf49a43SJulian Elischer FindCommand(const char *string) 4634cf49a43SJulian Elischer { 464f8307e12SArchie Cobbs int k, found = -1; 4654cf49a43SJulian Elischer 466f8307e12SArchie Cobbs for (k = 0; cmds[k] != NULL; k++) { 467f8307e12SArchie Cobbs if (MatchCommand(cmds[k], string)) { 4684cf49a43SJulian Elischer if (found != -1) { 4694cf49a43SJulian Elischer warnx("\"%s\": ambiguous command", string); 4704cf49a43SJulian Elischer return (NULL); 4714cf49a43SJulian Elischer } 4724cf49a43SJulian Elischer found = k; 4734cf49a43SJulian Elischer } 4744cf49a43SJulian Elischer } 4754cf49a43SJulian Elischer if (found == -1) { 4764cf49a43SJulian Elischer warnx("\"%s\": unknown command", string); 4774cf49a43SJulian Elischer return (NULL); 4784cf49a43SJulian Elischer } 4794cf49a43SJulian Elischer return (cmds[found]); 4804cf49a43SJulian Elischer } 4814cf49a43SJulian Elischer 4824cf49a43SJulian Elischer /* 483f8307e12SArchie Cobbs * See if string matches a prefix of "cmd" (or an alias) case insensitively 484f8307e12SArchie Cobbs */ 485f8307e12SArchie Cobbs static int 486f8307e12SArchie Cobbs MatchCommand(const struct ngcmd *cmd, const char *s) 487f8307e12SArchie Cobbs { 488f8307e12SArchie Cobbs int a; 489f8307e12SArchie Cobbs 490f8307e12SArchie Cobbs /* Try to match command, ignoring the usage stuff */ 491f8307e12SArchie Cobbs if (strlen(s) <= strcspn(cmd->cmd, WHITESPACE)) { 492f8307e12SArchie Cobbs if (strncasecmp(s, cmd->cmd, strlen(s)) == 0) 493f8307e12SArchie Cobbs return (1); 494f8307e12SArchie Cobbs } 495f8307e12SArchie Cobbs 496f8307e12SArchie Cobbs /* Try to match aliases */ 497f8307e12SArchie Cobbs for (a = 0; a < MAX_CMD_ALIAS && cmd->aliases[a] != NULL; a++) { 498f8307e12SArchie Cobbs if (strlen(cmd->aliases[a]) >= strlen(s)) { 499f8307e12SArchie Cobbs if (strncasecmp(s, cmd->aliases[a], strlen(s)) == 0) 500f8307e12SArchie Cobbs return (1); 501f8307e12SArchie Cobbs } 502f8307e12SArchie Cobbs } 503f8307e12SArchie Cobbs 504f8307e12SArchie Cobbs /* No match */ 505f8307e12SArchie Cobbs return (0); 506f8307e12SArchie Cobbs } 507f8307e12SArchie Cobbs 508f8307e12SArchie Cobbs /* 5094cf49a43SJulian Elischer * ReadCmd() 5104cf49a43SJulian Elischer */ 5114cf49a43SJulian Elischer static int 5124cf49a43SJulian Elischer ReadCmd(int ac, char **av) 5134cf49a43SJulian Elischer { 5144cf49a43SJulian Elischer FILE *fp; 5154cf49a43SJulian Elischer int rtn; 5164cf49a43SJulian Elischer 5174cf49a43SJulian Elischer /* Open file */ 5184cf49a43SJulian Elischer switch (ac) { 5194cf49a43SJulian Elischer case 2: 520f35e82dfSArchie Cobbs if ((fp = fopen(av[1], "r")) == NULL) { 5214cf49a43SJulian Elischer warn("%s", av[1]); 5224cf49a43SJulian Elischer return (CMDRTN_ERROR); 523f35e82dfSArchie Cobbs } 524f35e82dfSArchie Cobbs break; 5254cf49a43SJulian Elischer default: 5264cf49a43SJulian Elischer return (CMDRTN_USAGE); 5274cf49a43SJulian Elischer } 5284cf49a43SJulian Elischer 5294cf49a43SJulian Elischer /* Process it */ 5304cf49a43SJulian Elischer rtn = ReadFile(fp); 5314cf49a43SJulian Elischer fclose(fp); 5324cf49a43SJulian Elischer return (rtn); 5334cf49a43SJulian Elischer } 5344cf49a43SJulian Elischer 5354cf49a43SJulian Elischer /* 5364cf49a43SJulian Elischer * HelpCmd() 5374cf49a43SJulian Elischer */ 5384cf49a43SJulian Elischer static int 5394cf49a43SJulian Elischer HelpCmd(int ac, char **av) 5404cf49a43SJulian Elischer { 5414cf49a43SJulian Elischer const struct ngcmd *cmd; 5424cf49a43SJulian Elischer int k; 5434cf49a43SJulian Elischer 5444cf49a43SJulian Elischer switch (ac) { 5454cf49a43SJulian Elischer case 0: 5464cf49a43SJulian Elischer case 1: 5474cf49a43SJulian Elischer /* Show all commands */ 5484cf49a43SJulian Elischer printf("Available commands:\n"); 5494cf49a43SJulian Elischer for (k = 0; cmds[k] != NULL; k++) { 5504cf49a43SJulian Elischer char *s, buf[100]; 5514cf49a43SJulian Elischer 5524cf49a43SJulian Elischer cmd = cmds[k]; 5534cf49a43SJulian Elischer snprintf(buf, sizeof(buf), "%s", cmd->cmd); 5544cf49a43SJulian Elischer for (s = buf; *s != '\0' && !isspace(*s); s++); 5554cf49a43SJulian Elischer *s = '\0'; 5564cf49a43SJulian Elischer printf(" %-10s %s\n", buf, cmd->desc); 5574cf49a43SJulian Elischer } 5584cf49a43SJulian Elischer return (CMDRTN_OK); 5594cf49a43SJulian Elischer default: 5604cf49a43SJulian Elischer /* Show help on a specific command */ 5614cf49a43SJulian Elischer if ((cmd = FindCommand(av[1])) != NULL) { 562d3974088SDag-Erling Smørgrav printf("usage: %s\n", cmd->cmd); 563f8307e12SArchie Cobbs if (cmd->aliases[0] != NULL) { 564f8307e12SArchie Cobbs int a = 0; 565f8307e12SArchie Cobbs 566f8307e12SArchie Cobbs printf("Aliases: "); 567f8307e12SArchie Cobbs while (1) { 568f8307e12SArchie Cobbs printf("%s", cmd->aliases[a++]); 569f8307e12SArchie Cobbs if (a == MAX_CMD_ALIAS 570f8307e12SArchie Cobbs || cmd->aliases[a] == NULL) { 571f8307e12SArchie Cobbs printf("\n"); 572f8307e12SArchie Cobbs break; 573f8307e12SArchie Cobbs } 574f8307e12SArchie Cobbs printf(", "); 575f8307e12SArchie Cobbs } 576f8307e12SArchie Cobbs } 5774cf49a43SJulian Elischer printf("Summary: %s\n", cmd->desc); 5784cf49a43SJulian Elischer if (cmd->help != NULL) { 5794cf49a43SJulian Elischer const char *s; 5804cf49a43SJulian Elischer char buf[65]; 5814cf49a43SJulian Elischer int tot, len, done; 5824cf49a43SJulian Elischer 5834cf49a43SJulian Elischer printf("Description:\n"); 5844cf49a43SJulian Elischer for (s = cmd->help; *s != '\0'; s += len) { 5854cf49a43SJulian Elischer while (isspace(*s)) 5864cf49a43SJulian Elischer s++; 5874cf49a43SJulian Elischer tot = snprintf(buf, 5884cf49a43SJulian Elischer sizeof(buf), "%s", s); 5894cf49a43SJulian Elischer len = strlen(buf); 5904cf49a43SJulian Elischer done = len == tot; 5914cf49a43SJulian Elischer if (!done) { 5924cf49a43SJulian Elischer while (len > 0 5934cf49a43SJulian Elischer && !isspace(buf[len-1])) 5944cf49a43SJulian Elischer buf[--len] = '\0'; 5954cf49a43SJulian Elischer } 5964cf49a43SJulian Elischer printf(" %s\n", buf); 5974cf49a43SJulian Elischer } 5984cf49a43SJulian Elischer } 5994cf49a43SJulian Elischer } 6004cf49a43SJulian Elischer } 6014cf49a43SJulian Elischer return (CMDRTN_OK); 6024cf49a43SJulian Elischer } 6034cf49a43SJulian Elischer 6044cf49a43SJulian Elischer /* 6054cf49a43SJulian Elischer * QuitCmd() 6064cf49a43SJulian Elischer */ 6074cf49a43SJulian Elischer static int 608723c1c2eSRuslan Ermilov QuitCmd(int ac __unused, char **av __unused) 6094cf49a43SJulian Elischer { 6104cf49a43SJulian Elischer return (CMDRTN_QUIT); 6114cf49a43SJulian Elischer } 6124cf49a43SJulian Elischer 6134cf49a43SJulian Elischer /* 614f8307e12SArchie Cobbs * Dump data in hex and ASCII form 615f8307e12SArchie Cobbs */ 6166ebb8ebbSArchie Cobbs void 617f8307e12SArchie Cobbs DumpAscii(const u_char *buf, int len) 618f8307e12SArchie Cobbs { 619f8307e12SArchie Cobbs char ch, sbuf[100]; 620f8307e12SArchie Cobbs int k, count; 621f8307e12SArchie Cobbs 622f8307e12SArchie Cobbs for (count = 0; count < len; count += DUMP_BYTES_PER_LINE) { 623f8307e12SArchie Cobbs snprintf(sbuf, sizeof(sbuf), "%04x: ", count); 624f8307e12SArchie Cobbs for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 625f8307e12SArchie Cobbs if (count + k < len) { 626f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), 627f8307e12SArchie Cobbs sizeof(sbuf) - strlen(sbuf), 628f8307e12SArchie Cobbs "%02x ", buf[count + k]); 629f8307e12SArchie Cobbs } else { 630f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), 631f8307e12SArchie Cobbs sizeof(sbuf) - strlen(sbuf), " "); 632f8307e12SArchie Cobbs } 633f8307e12SArchie Cobbs } 634f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " "); 635f8307e12SArchie Cobbs for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 636f8307e12SArchie Cobbs if (count + k < len) { 637f8307e12SArchie Cobbs ch = isprint(buf[count + k]) ? 638f8307e12SArchie Cobbs buf[count + k] : '.'; 639f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), 640f8307e12SArchie Cobbs sizeof(sbuf) - strlen(sbuf), "%c", ch); 641f8307e12SArchie Cobbs } else { 642f8307e12SArchie Cobbs snprintf(sbuf + strlen(sbuf), 643f8307e12SArchie Cobbs sizeof(sbuf) - strlen(sbuf), " "); 644f8307e12SArchie Cobbs } 645f8307e12SArchie Cobbs } 646f8307e12SArchie Cobbs printf("%s\n", sbuf); 647f8307e12SArchie Cobbs } 648f8307e12SArchie Cobbs } 649f8307e12SArchie Cobbs 650f8307e12SArchie Cobbs /* 6514cf49a43SJulian Elischer * Usage() 6524cf49a43SJulian Elischer */ 6534cf49a43SJulian Elischer static void 6544cf49a43SJulian Elischer Usage(const char *msg) 6554cf49a43SJulian Elischer { 6564cf49a43SJulian Elischer if (msg) 6574cf49a43SJulian Elischer warnx("%s", msg); 658b00304d4SPhilippe Charnier fprintf(stderr, 659b00304d4SPhilippe Charnier "usage: ngctl [-d] [-f file] [-n name] [command ...]\n"); 660b00304d4SPhilippe Charnier exit(EX_USAGE); 6614cf49a43SJulian Elischer } 662