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); 327277577Sglebius if (DoParseCommand(buf) == CMDRTN_QUIT) { 328277577Sglebius pthread_mutex_unlock(&mutex); 329161044Sglebius break; 330277577Sglebius } 331161044Sglebius pthread_cond_signal(&cond); 332161044Sglebius pthread_mutex_unlock(&mutex); 333161044Sglebius } 334161044Sglebius 335161044Sglebius history_end(hist); 336161044Sglebius el_end(el); 337161044Sglebius pthread_cancel(monitor); 338161044Sglebius 339161044Sglebius return (CMDRTN_QUIT); 340161044Sglebius} 341161044Sglebius 342161044Sglebius#else /* !EDITLINE */ 343161044Sglebius 344161044Sglebius/* 345161044Sglebius * Interactive mode w/o libedit functionality. 346161044Sglebius */ 347161044Sglebiusstatic int 348161044SglebiusDoInteractive(void) 349161044Sglebius{ 35053913Sarchie const int maxfd = MAX(csock, dsock) + 1; 35152419Sjulian 35252419Sjulian (*help_cmd.func)(0, NULL); 35353913Sarchie while (1) { 35453913Sarchie struct timeval tv; 35553913Sarchie fd_set rfds; 35653913Sarchie 35753913Sarchie /* See if any data or control messages are arriving */ 35853913Sarchie FD_ZERO(&rfds); 35953913Sarchie FD_SET(csock, &rfds); 36053913Sarchie FD_SET(dsock, &rfds); 36153913Sarchie memset(&tv, 0, sizeof(tv)); 36253913Sarchie if (select(maxfd, &rfds, NULL, NULL, &tv) <= 0) { 36353913Sarchie 36453913Sarchie /* Issue prompt and wait for anything to happen */ 36553913Sarchie printf("%s", PROMPT); 36653913Sarchie fflush(stdout); 36753913Sarchie FD_ZERO(&rfds); 36853913Sarchie FD_SET(0, &rfds); 36953913Sarchie FD_SET(csock, &rfds); 37053913Sarchie FD_SET(dsock, &rfds); 37153913Sarchie if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) 37253913Sarchie err(EX_OSERR, "select"); 37353913Sarchie 37453913Sarchie /* If not user input, print a newline first */ 37553913Sarchie if (!FD_ISSET(0, &rfds)) 37653913Sarchie printf("\n"); 37753913Sarchie } 37853913Sarchie 379161071Sglebius ReadSockets(&rfds); 38053913Sarchie 38153913Sarchie /* Get any user input */ 38253913Sarchie if (FD_ISSET(0, &rfds)) { 38374383Sphk char buf[LINE_MAX]; 38474383Sphk 38574383Sphk if (fgets(buf, sizeof(buf), stdin) == NULL) { 38674383Sphk printf("\n"); 38753913Sarchie break; 38874383Sphk } 38974383Sphk if (DoParseCommand(buf) == CMDRTN_QUIT) 39074383Sphk break; 39153913Sarchie } 39253913Sarchie } 393160002Sglebius return (CMDRTN_QUIT); 39452419Sjulian} 395161044Sglebius#endif /* !EDITLINE */ 39652419Sjulian 39752419Sjulian/* 398161044Sglebius * Read and process data on netgraph control and data sockets. 399161044Sglebius */ 400161044Sglebiusstatic void 401161071SglebiusReadSockets(fd_set *rfds) 402161044Sglebius{ 403161044Sglebius /* Display any incoming control message. */ 404161071Sglebius if (FD_ISSET(csock, rfds)) 405161044Sglebius MsgRead(); 406161044Sglebius 407161044Sglebius /* Display any incoming data packet. */ 408161071Sglebius if (FD_ISSET(dsock, rfds)) { 409161044Sglebius char hook[NG_HOOKSIZ]; 410161044Sglebius u_char *buf; 411161044Sglebius int rl; 412161044Sglebius 413161044Sglebius /* Read packet from socket. */ 414161044Sglebius if ((rl = NgAllocRecvData(dsock, &buf, hook)) < 0) 415161044Sglebius err(EX_OSERR, "reading hook \"%s\"", hook); 416161044Sglebius if (rl == 0) 417161044Sglebius errx(EX_OSERR, "EOF from hook \"%s\"?", hook); 418161044Sglebius 419161044Sglebius /* Write packet to stdout. */ 420161044Sglebius printf("Rec'd data packet on hook \"%s\":\n", hook); 421161044Sglebius DumpAscii(buf, rl); 422161044Sglebius free(buf); 423161044Sglebius } 424161044Sglebius} 425161044Sglebius 426161044Sglebius/* 42752419Sjulian * Parse a command line and execute the command 42852419Sjulian */ 42952419Sjulianstatic int 430180076SmtmDoParseCommand(const char *line) 43152419Sjulian{ 43252419Sjulian char *av[MAX_ARGS]; 43352419Sjulian int ac; 43452419Sjulian 43552419Sjulian /* Parse line */ 436180076Smtm for (ac = 0, av[0] = strtok((char *)line, WHITESPACE); 43752419Sjulian ac < MAX_ARGS - 1 && av[ac]; 43852419Sjulian av[++ac] = strtok(NULL, WHITESPACE)); 43952419Sjulian 44052419Sjulian /* Do command */ 441160002Sglebius return (DoCommand(ac, av)); 44252419Sjulian} 44352419Sjulian 44452419Sjulian/* 44552419Sjulian * Execute the command 44652419Sjulian */ 44752419Sjulianstatic int 44852419SjulianDoCommand(int ac, char **av) 44952419Sjulian{ 45052419Sjulian const struct ngcmd *cmd; 45152419Sjulian int rtn; 45252419Sjulian 45352419Sjulian if (ac == 0 || *av[0] == 0) 454160002Sglebius return (CMDRTN_OK); 45552419Sjulian if ((cmd = FindCommand(av[0])) == NULL) 456160002Sglebius return (CMDRTN_ERROR); 45752419Sjulian if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE) 45852419Sjulian warnx("usage: %s", cmd->cmd); 459160002Sglebius return (rtn); 46052419Sjulian} 46152419Sjulian 46252419Sjulian/* 46352419Sjulian * Find a command 46452419Sjulian */ 46552419Sjulianstatic const struct ngcmd * 46652419SjulianFindCommand(const char *string) 46752419Sjulian{ 46853913Sarchie int k, found = -1; 46952419Sjulian 47053913Sarchie for (k = 0; cmds[k] != NULL; k++) { 47153913Sarchie if (MatchCommand(cmds[k], string)) { 47252419Sjulian if (found != -1) { 47352419Sjulian warnx("\"%s\": ambiguous command", string); 474160002Sglebius return (NULL); 47552419Sjulian } 47652419Sjulian found = k; 47752419Sjulian } 47852419Sjulian } 47952419Sjulian if (found == -1) { 48052419Sjulian warnx("\"%s\": unknown command", string); 481160002Sglebius return (NULL); 48252419Sjulian } 483160002Sglebius return (cmds[found]); 48452419Sjulian} 48552419Sjulian 48652419Sjulian/* 48753913Sarchie * See if string matches a prefix of "cmd" (or an alias) case insensitively 48853913Sarchie */ 48953913Sarchiestatic int 49053913SarchieMatchCommand(const struct ngcmd *cmd, const char *s) 49153913Sarchie{ 49253913Sarchie int a; 49353913Sarchie 49453913Sarchie /* Try to match command, ignoring the usage stuff */ 49553913Sarchie if (strlen(s) <= strcspn(cmd->cmd, WHITESPACE)) { 49653913Sarchie if (strncasecmp(s, cmd->cmd, strlen(s)) == 0) 49753913Sarchie return (1); 49853913Sarchie } 49953913Sarchie 50053913Sarchie /* Try to match aliases */ 50153913Sarchie for (a = 0; a < MAX_CMD_ALIAS && cmd->aliases[a] != NULL; a++) { 50253913Sarchie if (strlen(cmd->aliases[a]) >= strlen(s)) { 50353913Sarchie if (strncasecmp(s, cmd->aliases[a], strlen(s)) == 0) 50453913Sarchie return (1); 50553913Sarchie } 50653913Sarchie } 50753913Sarchie 50853913Sarchie /* No match */ 50953913Sarchie return (0); 51053913Sarchie} 51153913Sarchie 51253913Sarchie/* 51352419Sjulian * ReadCmd() 51452419Sjulian */ 51552419Sjulianstatic int 51652419SjulianReadCmd(int ac, char **av) 51752419Sjulian{ 51852419Sjulian FILE *fp; 51952419Sjulian int rtn; 52052419Sjulian 52152419Sjulian /* Open file */ 52252419Sjulian switch (ac) { 52352419Sjulian case 2: 52466904Sarchie if ((fp = fopen(av[1], "r")) == NULL) { 52552419Sjulian warn("%s", av[1]); 526160002Sglebius return (CMDRTN_ERROR); 52766904Sarchie } 52866904Sarchie break; 52952419Sjulian default: 530160002Sglebius return (CMDRTN_USAGE); 53152419Sjulian } 53252419Sjulian 53352419Sjulian /* Process it */ 53452419Sjulian rtn = ReadFile(fp); 53552419Sjulian fclose(fp); 536160002Sglebius return (rtn); 53752419Sjulian} 53852419Sjulian 53952419Sjulian/* 54052419Sjulian * HelpCmd() 54152419Sjulian */ 54252419Sjulianstatic int 54352419SjulianHelpCmd(int ac, char **av) 54452419Sjulian{ 54552419Sjulian const struct ngcmd *cmd; 54652419Sjulian int k; 54752419Sjulian 54852419Sjulian switch (ac) { 54952419Sjulian case 0: 55052419Sjulian case 1: 55152419Sjulian /* Show all commands */ 55252419Sjulian printf("Available commands:\n"); 55352419Sjulian for (k = 0; cmds[k] != NULL; k++) { 55452419Sjulian char *s, buf[100]; 55552419Sjulian 55652419Sjulian cmd = cmds[k]; 55752419Sjulian snprintf(buf, sizeof(buf), "%s", cmd->cmd); 55852419Sjulian for (s = buf; *s != '\0' && !isspace(*s); s++); 55952419Sjulian *s = '\0'; 56052419Sjulian printf(" %-10s %s\n", buf, cmd->desc); 56152419Sjulian } 562160002Sglebius return (CMDRTN_OK); 56352419Sjulian default: 56452419Sjulian /* Show help on a specific command */ 56552419Sjulian if ((cmd = FindCommand(av[1])) != NULL) { 56695258Sdes printf("usage: %s\n", cmd->cmd); 56753913Sarchie if (cmd->aliases[0] != NULL) { 56853913Sarchie int a = 0; 56953913Sarchie 57053913Sarchie printf("Aliases: "); 57153913Sarchie while (1) { 57253913Sarchie printf("%s", cmd->aliases[a++]); 57353913Sarchie if (a == MAX_CMD_ALIAS 57453913Sarchie || cmd->aliases[a] == NULL) { 57553913Sarchie printf("\n"); 57653913Sarchie break; 57753913Sarchie } 57853913Sarchie printf(", "); 57953913Sarchie } 58053913Sarchie } 58152419Sjulian printf("Summary: %s\n", cmd->desc); 58252419Sjulian if (cmd->help != NULL) { 58352419Sjulian const char *s; 58452419Sjulian char buf[65]; 58552419Sjulian int tot, len, done; 58652419Sjulian 58752419Sjulian printf("Description:\n"); 58852419Sjulian for (s = cmd->help; *s != '\0'; s += len) { 58952419Sjulian while (isspace(*s)) 59052419Sjulian s++; 59152419Sjulian tot = snprintf(buf, 59252419Sjulian sizeof(buf), "%s", s); 59352419Sjulian len = strlen(buf); 59452419Sjulian done = len == tot; 59552419Sjulian if (!done) { 59652419Sjulian while (len > 0 59752419Sjulian && !isspace(buf[len-1])) 59852419Sjulian buf[--len] = '\0'; 59952419Sjulian } 60052419Sjulian printf(" %s\n", buf); 60152419Sjulian } 60252419Sjulian } 60352419Sjulian } 60452419Sjulian } 605160002Sglebius return (CMDRTN_OK); 60652419Sjulian} 60752419Sjulian 60852419Sjulian/* 60952419Sjulian * QuitCmd() 61052419Sjulian */ 61152419Sjulianstatic int 612125011SruQuitCmd(int ac __unused, char **av __unused) 61352419Sjulian{ 614160002Sglebius return (CMDRTN_QUIT); 61552419Sjulian} 61652419Sjulian 61752419Sjulian/* 61853913Sarchie * Dump data in hex and ASCII form 61953913Sarchie */ 62061880Sarchievoid 62153913SarchieDumpAscii(const u_char *buf, int len) 62253913Sarchie{ 62353913Sarchie char ch, sbuf[100]; 62453913Sarchie int k, count; 62553913Sarchie 62653913Sarchie for (count = 0; count < len; count += DUMP_BYTES_PER_LINE) { 62753913Sarchie snprintf(sbuf, sizeof(sbuf), "%04x: ", count); 62853913Sarchie for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 62953913Sarchie if (count + k < len) { 63053913Sarchie snprintf(sbuf + strlen(sbuf), 63153913Sarchie sizeof(sbuf) - strlen(sbuf), 63253913Sarchie "%02x ", buf[count + k]); 63353913Sarchie } else { 63453913Sarchie snprintf(sbuf + strlen(sbuf), 63553913Sarchie sizeof(sbuf) - strlen(sbuf), " "); 63653913Sarchie } 63753913Sarchie } 63853913Sarchie snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " "); 63953913Sarchie for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 64053913Sarchie if (count + k < len) { 64153913Sarchie ch = isprint(buf[count + k]) ? 64253913Sarchie buf[count + k] : '.'; 64353913Sarchie snprintf(sbuf + strlen(sbuf), 64453913Sarchie sizeof(sbuf) - strlen(sbuf), "%c", ch); 64553913Sarchie } else { 64653913Sarchie snprintf(sbuf + strlen(sbuf), 64753913Sarchie sizeof(sbuf) - strlen(sbuf), " "); 64853913Sarchie } 64953913Sarchie } 65053913Sarchie printf("%s\n", sbuf); 65153913Sarchie } 65253913Sarchie} 65353913Sarchie 65453913Sarchie/* 65552419Sjulian * Usage() 65652419Sjulian */ 65752419Sjulianstatic void 65852419SjulianUsage(const char *msg) 65952419Sjulian{ 66052419Sjulian if (msg) 66152419Sjulian warnx("%s", msg); 662124130Scharnier fprintf(stderr, 663124130Scharnier "usage: ngctl [-d] [-f file] [-n name] [command ...]\n"); 664124130Scharnier exit(EX_USAGE); 66552419Sjulian} 666