152419Sjulian 252419Sjulian/* 352419Sjulian * main.c 452419Sjulian * 552419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 652419Sjulian * All rights reserved. 752419Sjulian * 852419Sjulian * Subject to the following obligations and disclaimer of warranty, use and 952419Sjulian * redistribution of this software, in source or object code forms, with or 1052419Sjulian * without modifications are expressly permitted by Whistle Communications; 1152419Sjulian * provided, however, that: 1252419Sjulian * 1. Any and all reproductions of the source or object code must include the 1352419Sjulian * copyright notice above and the following disclaimer of warranties; and 1452419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle 1552419Sjulian * Communications, Inc. trademarks, including the mark "WHISTLE 1652419Sjulian * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1752419Sjulian * such appears in the above copyright notice or in the software. 1852419Sjulian * 1952419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2052419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2152419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2252419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2352419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2452419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2552419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2652419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2752419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2852419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 2952419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3052419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3152419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3252419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3352419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3452419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3552419Sjulian * OF SUCH DAMAGE. 3652419Sjulian * 3753913Sarchie * $Whistle: main.c,v 1.12 1999/11/29 19:17:46 archie Exp $ 3852419Sjulian */ 3952419Sjulian 40216588Scharnier#include <sys/cdefs.h> 41216588Scharnier__FBSDID("$FreeBSD$"); 42216588Scharnier 43158882Sglebius#include <sys/param.h> 44158882Sglebius#include <sys/socket.h> 45158882Sglebius#include <sys/select.h> 46158882Sglebius 47158882Sglebius#include <ctype.h> 48158882Sglebius#include <err.h> 49158882Sglebius#include <errno.h> 50158882Sglebius#include <limits.h> 51158882Sglebius#include <stdio.h> 52158882Sglebius#include <stdlib.h> 53158882Sglebius#include <string.h> 54158882Sglebius#include <sysexits.h> 55158882Sglebius#include <unistd.h> 56161044Sglebius#ifdef EDITLINE 57161044Sglebius#include <signal.h> 58161044Sglebius#include <histedit.h> 59161044Sglebius#include <pthread.h> 60161044Sglebius#endif 61158882Sglebius 62158882Sglebius#include <netgraph.h> 63158882Sglebius 6452419Sjulian#include "ngctl.h" 6552419Sjulian 6653913Sarchie#define PROMPT "+ " 6753913Sarchie#define MAX_ARGS 512 6853913Sarchie#define WHITESPACE " \t\r\n\v\f" 6953913Sarchie#define DUMP_BYTES_PER_LINE 16 7052419Sjulian 7152419Sjulian/* Internal functions */ 7252419Sjulianstatic int ReadFile(FILE *fp); 73161071Sglebiusstatic void ReadSockets(fd_set *); 74180076Smtmstatic int DoParseCommand(const char *line); 7552419Sjulianstatic int DoCommand(int ac, char **av); 7652419Sjulianstatic int DoInteractive(void); 7752419Sjulianstatic const struct ngcmd *FindCommand(const char *string); 7853913Sarchiestatic int MatchCommand(const struct ngcmd *cmd, const char *s); 7952419Sjulianstatic void Usage(const char *msg); 8052419Sjulianstatic int ReadCmd(int ac, char **av); 8152419Sjulianstatic int HelpCmd(int ac, char **av); 8252419Sjulianstatic int QuitCmd(int ac, char **av); 83161044Sglebius#ifdef EDITLINE 84194217Sdesstatic volatile sig_atomic_t unblock; 85161044Sglebiusstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 86161044Sglebiusstatic pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 87161044Sglebius#endif 8852419Sjulian 8952419Sjulian/* List of commands */ 9052419Sjulianstatic const struct ngcmd *const cmds[] = { 9162471Sphk &config_cmd, 9252419Sjulian &connect_cmd, 9352419Sjulian &debug_cmd, 94124271Sgreen &dot_cmd, 9552419Sjulian &help_cmd, 9652419Sjulian &list_cmd, 9752419Sjulian &mkpeer_cmd, 9853913Sarchie &msg_cmd, 9952419Sjulian &name_cmd, 10052419Sjulian &read_cmd, 10152419Sjulian &rmhook_cmd, 10252419Sjulian &show_cmd, 10352419Sjulian &shutdown_cmd, 10452419Sjulian &status_cmd, 10552419Sjulian &types_cmd, 10689674Sarchie &write_cmd, 10752419Sjulian &quit_cmd, 10852419Sjulian NULL 10952419Sjulian}; 11052419Sjulian 11152419Sjulian/* Commands defined in this file */ 11252419Sjulianconst struct ngcmd read_cmd = { 11352419Sjulian ReadCmd, 11452419Sjulian "read <filename>", 11552419Sjulian "Read and execute commands from a file", 11653913Sarchie NULL, 11753913Sarchie { "source", "." } 11852419Sjulian}; 11952419Sjulianconst struct ngcmd help_cmd = { 12052419Sjulian HelpCmd, 12152419Sjulian "help [command]", 12252419Sjulian "Show command summary or get more help on a specific command", 12353913Sarchie NULL, 12453913Sarchie { "?" } 12552419Sjulian}; 12652419Sjulianconst struct ngcmd quit_cmd = { 12752419Sjulian QuitCmd, 12852419Sjulian "quit", 12952419Sjulian "Exit program", 13053913Sarchie NULL, 13153913Sarchie { "exit" } 13252419Sjulian}; 13352419Sjulian 13452419Sjulian/* Our control and data sockets */ 13552419Sjulianint csock, dsock; 13652419Sjulian 13752419Sjulian/* 13852419Sjulian * main() 13952419Sjulian */ 14052419Sjulianint 14152419Sjulianmain(int ac, char *av[]) 14252419Sjulian{ 143122556Sharti char name[NG_NODESIZ]; 14452419Sjulian int interactive = isatty(0) && isatty(1); 14552419Sjulian FILE *fp = NULL; 146141303Smaxim int ch, rtn = 0; 14752419Sjulian 14852419Sjulian /* Set default node name */ 14952419Sjulian snprintf(name, sizeof(name), "ngctl%d", getpid()); 15052419Sjulian 15152419Sjulian /* Parse command line */ 152166529Skevlo while ((ch = getopt(ac, av, "df:n:")) != -1) { 15352419Sjulian switch (ch) { 15452419Sjulian case 'd': 15552419Sjulian NgSetDebug(NgSetDebug(-1) + 1); 15652419Sjulian break; 15752419Sjulian case 'f': 15852419Sjulian if (strcmp(optarg, "-") == 0) 15952419Sjulian fp = stdin; 16052419Sjulian else if ((fp = fopen(optarg, "r")) == NULL) 16152419Sjulian err(EX_NOINPUT, "%s", optarg); 16252419Sjulian break; 16352419Sjulian case 'n': 16452419Sjulian snprintf(name, sizeof(name), "%s", optarg); 16552419Sjulian break; 16652419Sjulian case '?': 16752419Sjulian default: 16852419Sjulian Usage((char *)NULL); 16952419Sjulian break; 17052419Sjulian } 17152419Sjulian } 17252419Sjulian ac -= optind; 17352419Sjulian av += optind; 17452419Sjulian 17552419Sjulian /* Create a new socket node */ 17656709Sarchie if (NgMkSockNode(name, &csock, &dsock) < 0) 17752419Sjulian err(EX_OSERR, "can't create node"); 178141303Smaxim 17952419Sjulian /* Do commands as requested */ 18052419Sjulian if (ac == 0) { 18152419Sjulian if (fp != NULL) { 18252419Sjulian rtn = ReadFile(fp); 18352419Sjulian } else if (interactive) { 18452419Sjulian rtn = DoInteractive(); 18552419Sjulian } else 18652419Sjulian Usage("no command specified"); 18752419Sjulian } else { 18852419Sjulian rtn = DoCommand(ac, av); 18952419Sjulian } 19052419Sjulian 19152419Sjulian /* Convert command return code into system exit code */ 19252419Sjulian switch (rtn) { 19352419Sjulian case CMDRTN_OK: 19452419Sjulian case CMDRTN_QUIT: 19552419Sjulian rtn = 0; 19652419Sjulian break; 19752419Sjulian case CMDRTN_USAGE: 19852419Sjulian rtn = EX_USAGE; 19952419Sjulian break; 20052419Sjulian case CMDRTN_ERROR: 20152419Sjulian rtn = EX_OSERR; 20252419Sjulian break; 20352419Sjulian } 204160002Sglebius return (rtn); 20552419Sjulian} 20652419Sjulian 20752419Sjulian/* 20852419Sjulian * Process commands from a file 20952419Sjulian */ 21052419Sjulianstatic int 21152419SjulianReadFile(FILE *fp) 21252419Sjulian{ 21352419Sjulian char line[LINE_MAX]; 21452419Sjulian int num, rtn; 21552419Sjulian 21652419Sjulian for (num = 1; fgets(line, sizeof(line), fp) != NULL; num++) { 21752419Sjulian if (*line == '#') 21852419Sjulian continue; 21952419Sjulian if ((rtn = DoParseCommand(line)) != 0) { 22052419Sjulian warnx("line %d: error in file", num); 221160002Sglebius return (rtn); 22252419Sjulian } 22352419Sjulian } 224160002Sglebius return (CMDRTN_OK); 22552419Sjulian} 22652419Sjulian 227161044Sglebius#ifdef EDITLINE 228161044Sglebius/* Signal handler for Monitor() thread. */ 229161044Sglebiusstatic void 230216588ScharnierUnblock(int signal __unused) 231161044Sglebius{ 232161071Sglebius 233161044Sglebius unblock = 1; 234161044Sglebius} 235161044Sglebius 23652419Sjulian/* 237161044Sglebius * Thread that monitors csock and dsock while main thread 238161044Sglebius * can be blocked in el_gets(). 23952419Sjulian */ 240161044Sglebiusstatic void * 241216588ScharnierMonitor(void *v __unused) 242161044Sglebius{ 243161044Sglebius struct sigaction act; 244161044Sglebius const int maxfd = MAX(csock, dsock) + 1; 245161044Sglebius 246161044Sglebius act.sa_handler = Unblock; 247161044Sglebius sigemptyset(&act.sa_mask); 248161044Sglebius act.sa_flags = 0; 249161044Sglebius sigaction(SIGUSR1, &act, NULL); 250161044Sglebius 251161044Sglebius pthread_mutex_lock(&mutex); 252161044Sglebius for (;;) { 253161044Sglebius fd_set rfds; 254161044Sglebius 255161044Sglebius /* See if any data or control messages are arriving. */ 256161044Sglebius FD_ZERO(&rfds); 257161044Sglebius FD_SET(csock, &rfds); 258161044Sglebius FD_SET(dsock, &rfds); 259161044Sglebius unblock = 0; 260161044Sglebius if (select(maxfd, &rfds, NULL, NULL, NULL) <= 0) { 261161044Sglebius if (errno == EINTR) { 262161044Sglebius if (unblock == 1) 263161044Sglebius pthread_cond_wait(&cond, &mutex); 264161044Sglebius continue; 265161044Sglebius } 266161044Sglebius err(EX_OSERR, "select"); 267161044Sglebius } 268161071Sglebius ReadSockets(&rfds); 269161044Sglebius } 270161044Sglebius 271161044Sglebius return (NULL); 272161044Sglebius} 273161044Sglebius 274161044Sglebiusstatic char * 275216588ScharnierPrompt(EditLine *el __unused) 276161044Sglebius{ 277161071Sglebius 278161071Sglebius return (PROMPT); 279161044Sglebius} 280161044Sglebius 281161044Sglebius/* 282161044Sglebius * Here we start a thread, that will monitor the netgraph 283161044Sglebius * sockets and catch any unexpected messages or data on them, 284161044Sglebius * that can arrive while user edits his/her commands. 285161044Sglebius * 286161044Sglebius * Whenever we expect data on netgraph sockets, we send signal 287161044Sglebius * to monitoring thread. The signal forces it to exit select() 288161044Sglebius * system call and sleep on condvar until we wake it. While 289161044Sglebius * monitoring thread sleeps, we can do our work with netgraph 290161044Sglebius * sockets. 291161044Sglebius */ 29252419Sjulianstatic int 29352419SjulianDoInteractive(void) 29452419Sjulian{ 295161044Sglebius pthread_t monitor; 296161044Sglebius EditLine *el; 297161044Sglebius History *hist; 298161044Sglebius HistEvent hev = { 0, "" }; 299161044Sglebius 300161044Sglebius (*help_cmd.func)(0, NULL); 301161044Sglebius pthread_create(&monitor, NULL, Monitor, NULL); 302161044Sglebius el = el_init(getprogname(), stdin, stdout, stderr); 303161044Sglebius if (el == NULL) 304161044Sglebius return (CMDRTN_ERROR); 305161044Sglebius el_set(el, EL_PROMPT, Prompt); 306161044Sglebius el_set(el, EL_SIGNAL, 1); 307161044Sglebius el_set(el, EL_EDITOR, "emacs"); 308161044Sglebius hist = history_init(); 309161044Sglebius if (hist == NULL) 310161044Sglebius return (CMDRTN_ERROR); 311161044Sglebius history(hist, &hev, H_SETSIZE, 100); 312161044Sglebius history(hist, &hev, H_SETUNIQUE, 1); 313161044Sglebius el_set(el, EL_HIST, history, (const char *)hist); 314161044Sglebius el_source(el, NULL); 315161044Sglebius 316161044Sglebius for (;;) { 317161044Sglebius const char *buf; 318161044Sglebius int count; 319161044Sglebius 320161044Sglebius if ((buf = el_gets(el, &count)) == NULL) { 321161044Sglebius printf("\n"); 322161044Sglebius break; 323161044Sglebius } 324161044Sglebius history(hist, &hev, H_ENTER, buf); 325161044Sglebius pthread_kill(monitor, SIGUSR1); 326161044Sglebius pthread_mutex_lock(&mutex); 327180076Smtm if (DoParseCommand(buf) == CMDRTN_QUIT) 328161044Sglebius break; 329161044Sglebius pthread_cond_signal(&cond); 330161044Sglebius pthread_mutex_unlock(&mutex); 331161044Sglebius } 332161044Sglebius 333161044Sglebius history_end(hist); 334161044Sglebius el_end(el); 335161044Sglebius pthread_cancel(monitor); 336161044Sglebius 337161044Sglebius return (CMDRTN_QUIT); 338161044Sglebius} 339161044Sglebius 340161044Sglebius#else /* !EDITLINE */ 341161044Sglebius 342161044Sglebius/* 343161044Sglebius * Interactive mode w/o libedit functionality. 344161044Sglebius */ 345161044Sglebiusstatic int 346161044SglebiusDoInteractive(void) 347161044Sglebius{ 34853913Sarchie const int maxfd = MAX(csock, dsock) + 1; 34952419Sjulian 35052419Sjulian (*help_cmd.func)(0, NULL); 35153913Sarchie while (1) { 35253913Sarchie struct timeval tv; 35353913Sarchie fd_set rfds; 35453913Sarchie 35553913Sarchie /* See if any data or control messages are arriving */ 35653913Sarchie FD_ZERO(&rfds); 35753913Sarchie FD_SET(csock, &rfds); 35853913Sarchie FD_SET(dsock, &rfds); 35953913Sarchie memset(&tv, 0, sizeof(tv)); 36053913Sarchie if (select(maxfd, &rfds, NULL, NULL, &tv) <= 0) { 36153913Sarchie 36253913Sarchie /* Issue prompt and wait for anything to happen */ 36353913Sarchie printf("%s", PROMPT); 36453913Sarchie fflush(stdout); 36553913Sarchie FD_ZERO(&rfds); 36653913Sarchie FD_SET(0, &rfds); 36753913Sarchie FD_SET(csock, &rfds); 36853913Sarchie FD_SET(dsock, &rfds); 36953913Sarchie if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) 37053913Sarchie err(EX_OSERR, "select"); 37153913Sarchie 37253913Sarchie /* If not user input, print a newline first */ 37353913Sarchie if (!FD_ISSET(0, &rfds)) 37453913Sarchie printf("\n"); 37553913Sarchie } 37653913Sarchie 377161071Sglebius ReadSockets(&rfds); 37853913Sarchie 37953913Sarchie /* Get any user input */ 38053913Sarchie if (FD_ISSET(0, &rfds)) { 38174383Sphk char buf[LINE_MAX]; 38274383Sphk 38374383Sphk if (fgets(buf, sizeof(buf), stdin) == NULL) { 38474383Sphk printf("\n"); 38553913Sarchie break; 38674383Sphk } 38774383Sphk if (DoParseCommand(buf) == CMDRTN_QUIT) 38874383Sphk break; 38953913Sarchie } 39053913Sarchie } 391160002Sglebius return (CMDRTN_QUIT); 39252419Sjulian} 393161044Sglebius#endif /* !EDITLINE */ 39452419Sjulian 39552419Sjulian/* 396161044Sglebius * Read and process data on netgraph control and data sockets. 397161044Sglebius */ 398161044Sglebiusstatic void 399161071SglebiusReadSockets(fd_set *rfds) 400161044Sglebius{ 401161044Sglebius /* Display any incoming control message. */ 402161071Sglebius if (FD_ISSET(csock, rfds)) 403161044Sglebius MsgRead(); 404161044Sglebius 405161044Sglebius /* Display any incoming data packet. */ 406161071Sglebius if (FD_ISSET(dsock, rfds)) { 407161044Sglebius char hook[NG_HOOKSIZ]; 408161044Sglebius u_char *buf; 409161044Sglebius int rl; 410161044Sglebius 411161044Sglebius /* Read packet from socket. */ 412161044Sglebius if ((rl = NgAllocRecvData(dsock, &buf, hook)) < 0) 413161044Sglebius err(EX_OSERR, "reading hook \"%s\"", hook); 414161044Sglebius if (rl == 0) 415161044Sglebius errx(EX_OSERR, "EOF from hook \"%s\"?", hook); 416161044Sglebius 417161044Sglebius /* Write packet to stdout. */ 418161044Sglebius printf("Rec'd data packet on hook \"%s\":\n", hook); 419161044Sglebius DumpAscii(buf, rl); 420161044Sglebius free(buf); 421161044Sglebius } 422161044Sglebius} 423161044Sglebius 424161044Sglebius/* 42552419Sjulian * Parse a command line and execute the command 42652419Sjulian */ 42752419Sjulianstatic int 428180076SmtmDoParseCommand(const char *line) 42952419Sjulian{ 43052419Sjulian char *av[MAX_ARGS]; 43152419Sjulian int ac; 43252419Sjulian 43352419Sjulian /* Parse line */ 434180076Smtm for (ac = 0, av[0] = strtok((char *)line, WHITESPACE); 43552419Sjulian ac < MAX_ARGS - 1 && av[ac]; 43652419Sjulian av[++ac] = strtok(NULL, WHITESPACE)); 43752419Sjulian 43852419Sjulian /* Do command */ 439160002Sglebius return (DoCommand(ac, av)); 44052419Sjulian} 44152419Sjulian 44252419Sjulian/* 44352419Sjulian * Execute the command 44452419Sjulian */ 44552419Sjulianstatic int 44652419SjulianDoCommand(int ac, char **av) 44752419Sjulian{ 44852419Sjulian const struct ngcmd *cmd; 44952419Sjulian int rtn; 45052419Sjulian 45152419Sjulian if (ac == 0 || *av[0] == 0) 452160002Sglebius return (CMDRTN_OK); 45352419Sjulian if ((cmd = FindCommand(av[0])) == NULL) 454160002Sglebius return (CMDRTN_ERROR); 45552419Sjulian if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE) 45652419Sjulian warnx("usage: %s", cmd->cmd); 457160002Sglebius return (rtn); 45852419Sjulian} 45952419Sjulian 46052419Sjulian/* 46152419Sjulian * Find a command 46252419Sjulian */ 46352419Sjulianstatic const struct ngcmd * 46452419SjulianFindCommand(const char *string) 46552419Sjulian{ 46653913Sarchie int k, found = -1; 46752419Sjulian 46853913Sarchie for (k = 0; cmds[k] != NULL; k++) { 46953913Sarchie if (MatchCommand(cmds[k], string)) { 47052419Sjulian if (found != -1) { 47152419Sjulian warnx("\"%s\": ambiguous command", string); 472160002Sglebius return (NULL); 47352419Sjulian } 47452419Sjulian found = k; 47552419Sjulian } 47652419Sjulian } 47752419Sjulian if (found == -1) { 47852419Sjulian warnx("\"%s\": unknown command", string); 479160002Sglebius return (NULL); 48052419Sjulian } 481160002Sglebius return (cmds[found]); 48252419Sjulian} 48352419Sjulian 48452419Sjulian/* 48553913Sarchie * See if string matches a prefix of "cmd" (or an alias) case insensitively 48653913Sarchie */ 48753913Sarchiestatic int 48853913SarchieMatchCommand(const struct ngcmd *cmd, const char *s) 48953913Sarchie{ 49053913Sarchie int a; 49153913Sarchie 49253913Sarchie /* Try to match command, ignoring the usage stuff */ 49353913Sarchie if (strlen(s) <= strcspn(cmd->cmd, WHITESPACE)) { 49453913Sarchie if (strncasecmp(s, cmd->cmd, strlen(s)) == 0) 49553913Sarchie return (1); 49653913Sarchie } 49753913Sarchie 49853913Sarchie /* Try to match aliases */ 49953913Sarchie for (a = 0; a < MAX_CMD_ALIAS && cmd->aliases[a] != NULL; a++) { 50053913Sarchie if (strlen(cmd->aliases[a]) >= strlen(s)) { 50153913Sarchie if (strncasecmp(s, cmd->aliases[a], strlen(s)) == 0) 50253913Sarchie return (1); 50353913Sarchie } 50453913Sarchie } 50553913Sarchie 50653913Sarchie /* No match */ 50753913Sarchie return (0); 50853913Sarchie} 50953913Sarchie 51053913Sarchie/* 51152419Sjulian * ReadCmd() 51252419Sjulian */ 51352419Sjulianstatic int 51452419SjulianReadCmd(int ac, char **av) 51552419Sjulian{ 51652419Sjulian FILE *fp; 51752419Sjulian int rtn; 51852419Sjulian 51952419Sjulian /* Open file */ 52052419Sjulian switch (ac) { 52152419Sjulian case 2: 52266904Sarchie if ((fp = fopen(av[1], "r")) == NULL) { 52352419Sjulian warn("%s", av[1]); 524160002Sglebius return (CMDRTN_ERROR); 52566904Sarchie } 52666904Sarchie break; 52752419Sjulian default: 528160002Sglebius return (CMDRTN_USAGE); 52952419Sjulian } 53052419Sjulian 53152419Sjulian /* Process it */ 53252419Sjulian rtn = ReadFile(fp); 53352419Sjulian fclose(fp); 534160002Sglebius return (rtn); 53552419Sjulian} 53652419Sjulian 53752419Sjulian/* 53852419Sjulian * HelpCmd() 53952419Sjulian */ 54052419Sjulianstatic int 54152419SjulianHelpCmd(int ac, char **av) 54252419Sjulian{ 54352419Sjulian const struct ngcmd *cmd; 54452419Sjulian int k; 54552419Sjulian 54652419Sjulian switch (ac) { 54752419Sjulian case 0: 54852419Sjulian case 1: 54952419Sjulian /* Show all commands */ 55052419Sjulian printf("Available commands:\n"); 55152419Sjulian for (k = 0; cmds[k] != NULL; k++) { 55252419Sjulian char *s, buf[100]; 55352419Sjulian 55452419Sjulian cmd = cmds[k]; 55552419Sjulian snprintf(buf, sizeof(buf), "%s", cmd->cmd); 55652419Sjulian for (s = buf; *s != '\0' && !isspace(*s); s++); 55752419Sjulian *s = '\0'; 55852419Sjulian printf(" %-10s %s\n", buf, cmd->desc); 55952419Sjulian } 560160002Sglebius return (CMDRTN_OK); 56152419Sjulian default: 56252419Sjulian /* Show help on a specific command */ 56352419Sjulian if ((cmd = FindCommand(av[1])) != NULL) { 56495258Sdes printf("usage: %s\n", cmd->cmd); 56553913Sarchie if (cmd->aliases[0] != NULL) { 56653913Sarchie int a = 0; 56753913Sarchie 56853913Sarchie printf("Aliases: "); 56953913Sarchie while (1) { 57053913Sarchie printf("%s", cmd->aliases[a++]); 57153913Sarchie if (a == MAX_CMD_ALIAS 57253913Sarchie || cmd->aliases[a] == NULL) { 57353913Sarchie printf("\n"); 57453913Sarchie break; 57553913Sarchie } 57653913Sarchie printf(", "); 57753913Sarchie } 57853913Sarchie } 57952419Sjulian printf("Summary: %s\n", cmd->desc); 58052419Sjulian if (cmd->help != NULL) { 58152419Sjulian const char *s; 58252419Sjulian char buf[65]; 58352419Sjulian int tot, len, done; 58452419Sjulian 58552419Sjulian printf("Description:\n"); 58652419Sjulian for (s = cmd->help; *s != '\0'; s += len) { 58752419Sjulian while (isspace(*s)) 58852419Sjulian s++; 58952419Sjulian tot = snprintf(buf, 59052419Sjulian sizeof(buf), "%s", s); 59152419Sjulian len = strlen(buf); 59252419Sjulian done = len == tot; 59352419Sjulian if (!done) { 59452419Sjulian while (len > 0 59552419Sjulian && !isspace(buf[len-1])) 59652419Sjulian buf[--len] = '\0'; 59752419Sjulian } 59852419Sjulian printf(" %s\n", buf); 59952419Sjulian } 60052419Sjulian } 60152419Sjulian } 60252419Sjulian } 603160002Sglebius return (CMDRTN_OK); 60452419Sjulian} 60552419Sjulian 60652419Sjulian/* 60752419Sjulian * QuitCmd() 60852419Sjulian */ 60952419Sjulianstatic int 610125011SruQuitCmd(int ac __unused, char **av __unused) 61152419Sjulian{ 612160002Sglebius return (CMDRTN_QUIT); 61352419Sjulian} 61452419Sjulian 61552419Sjulian/* 61653913Sarchie * Dump data in hex and ASCII form 61753913Sarchie */ 61861880Sarchievoid 61953913SarchieDumpAscii(const u_char *buf, int len) 62053913Sarchie{ 62153913Sarchie char ch, sbuf[100]; 62253913Sarchie int k, count; 62353913Sarchie 62453913Sarchie for (count = 0; count < len; count += DUMP_BYTES_PER_LINE) { 62553913Sarchie snprintf(sbuf, sizeof(sbuf), "%04x: ", count); 62653913Sarchie for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 62753913Sarchie if (count + k < len) { 62853913Sarchie snprintf(sbuf + strlen(sbuf), 62953913Sarchie sizeof(sbuf) - strlen(sbuf), 63053913Sarchie "%02x ", buf[count + k]); 63153913Sarchie } else { 63253913Sarchie snprintf(sbuf + strlen(sbuf), 63353913Sarchie sizeof(sbuf) - strlen(sbuf), " "); 63453913Sarchie } 63553913Sarchie } 63653913Sarchie snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " "); 63753913Sarchie for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 63853913Sarchie if (count + k < len) { 63953913Sarchie ch = isprint(buf[count + k]) ? 64053913Sarchie buf[count + k] : '.'; 64153913Sarchie snprintf(sbuf + strlen(sbuf), 64253913Sarchie sizeof(sbuf) - strlen(sbuf), "%c", ch); 64353913Sarchie } else { 64453913Sarchie snprintf(sbuf + strlen(sbuf), 64553913Sarchie sizeof(sbuf) - strlen(sbuf), " "); 64653913Sarchie } 64753913Sarchie } 64853913Sarchie printf("%s\n", sbuf); 64953913Sarchie } 65053913Sarchie} 65153913Sarchie 65253913Sarchie/* 65352419Sjulian * Usage() 65452419Sjulian */ 65552419Sjulianstatic void 65652419SjulianUsage(const char *msg) 65752419Sjulian{ 65852419Sjulian if (msg) 65952419Sjulian warnx("%s", msg); 660124130Scharnier fprintf(stderr, 661124130Scharnier "usage: ngctl [-d] [-f file] [-n name] [command ...]\n"); 662124130Scharnier exit(EX_USAGE); 66352419Sjulian} 664