main.c revision 66904
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 * 3752419Sjulian * $FreeBSD: head/usr.sbin/ngctl/main.c 66904 2000-10-10 01:34:20Z archie $ 3853913Sarchie * $Whistle: main.c,v 1.12 1999/11/29 19:17:46 archie Exp $ 3952419Sjulian */ 4052419Sjulian 4152419Sjulian#include "ngctl.h" 4252419Sjulian 4353913Sarchie#define PROMPT "+ " 4453913Sarchie#define MAX_ARGS 512 4553913Sarchie#define WHITESPACE " \t\r\n\v\f" 4653913Sarchie#define DUMP_BYTES_PER_LINE 16 4752419Sjulian 4852419Sjulian/* Internal functions */ 4952419Sjulianstatic int ReadFile(FILE *fp); 5052419Sjulianstatic int DoParseCommand(char *line); 5152419Sjulianstatic int DoCommand(int ac, char **av); 5252419Sjulianstatic int DoInteractive(void); 5352419Sjulianstatic const struct ngcmd *FindCommand(const char *string); 5453913Sarchiestatic int MatchCommand(const struct ngcmd *cmd, const char *s); 5552419Sjulianstatic void Usage(const char *msg); 5652419Sjulianstatic int ReadCmd(int ac, char **av); 5752419Sjulianstatic int HelpCmd(int ac, char **av); 5852419Sjulianstatic int QuitCmd(int ac, char **av); 5952419Sjulian 6052419Sjulian/* List of commands */ 6152419Sjulianstatic const struct ngcmd *const cmds[] = { 6262471Sphk &config_cmd, 6352419Sjulian &connect_cmd, 6452419Sjulian &debug_cmd, 6552419Sjulian &help_cmd, 6652419Sjulian &list_cmd, 6752419Sjulian &mkpeer_cmd, 6853913Sarchie &msg_cmd, 6952419Sjulian &name_cmd, 7052419Sjulian &read_cmd, 7152419Sjulian &rmhook_cmd, 7252419Sjulian &show_cmd, 7352419Sjulian &shutdown_cmd, 7452419Sjulian &status_cmd, 7552419Sjulian &types_cmd, 7652419Sjulian &quit_cmd, 7752419Sjulian NULL 7852419Sjulian}; 7952419Sjulian 8052419Sjulian/* Commands defined in this file */ 8152419Sjulianconst struct ngcmd read_cmd = { 8252419Sjulian ReadCmd, 8352419Sjulian "read <filename>", 8452419Sjulian "Read and execute commands from a file", 8553913Sarchie NULL, 8653913Sarchie { "source", "." } 8752419Sjulian}; 8852419Sjulianconst struct ngcmd help_cmd = { 8952419Sjulian HelpCmd, 9052419Sjulian "help [command]", 9152419Sjulian "Show command summary or get more help on a specific command", 9253913Sarchie NULL, 9353913Sarchie { "?" } 9452419Sjulian}; 9552419Sjulianconst struct ngcmd quit_cmd = { 9652419Sjulian QuitCmd, 9752419Sjulian "quit", 9852419Sjulian "Exit program", 9953913Sarchie NULL, 10053913Sarchie { "exit" } 10152419Sjulian}; 10252419Sjulian 10352419Sjulian/* Our control and data sockets */ 10452419Sjulianint csock, dsock; 10552419Sjulian 10652419Sjulian/* 10752419Sjulian * main() 10852419Sjulian */ 10952419Sjulianint 11052419Sjulianmain(int ac, char *av[]) 11152419Sjulian{ 11252419Sjulian char name[NG_NODELEN + 1]; 11352419Sjulian int interactive = isatty(0) && isatty(1); 11452419Sjulian FILE *fp = NULL; 11552419Sjulian int ch, rtn = 0; 11652419Sjulian 11752419Sjulian /* Set default node name */ 11852419Sjulian snprintf(name, sizeof(name), "ngctl%d", getpid()); 11952419Sjulian 12052419Sjulian /* Parse command line */ 12152419Sjulian while ((ch = getopt(ac, av, "df:n:")) != EOF) { 12252419Sjulian switch (ch) { 12352419Sjulian case 'd': 12452419Sjulian NgSetDebug(NgSetDebug(-1) + 1); 12552419Sjulian break; 12652419Sjulian case 'f': 12752419Sjulian if (strcmp(optarg, "-") == 0) 12852419Sjulian fp = stdin; 12952419Sjulian else if ((fp = fopen(optarg, "r")) == NULL) 13052419Sjulian err(EX_NOINPUT, "%s", optarg); 13152419Sjulian break; 13252419Sjulian case 'n': 13352419Sjulian snprintf(name, sizeof(name), "%s", optarg); 13452419Sjulian break; 13552419Sjulian case '?': 13652419Sjulian default: 13752419Sjulian Usage((char *)NULL); 13852419Sjulian break; 13952419Sjulian } 14052419Sjulian } 14152419Sjulian ac -= optind; 14252419Sjulian av += optind; 14352419Sjulian 14452419Sjulian /* Create a new socket node */ 14556709Sarchie if (NgMkSockNode(name, &csock, &dsock) < 0) 14652419Sjulian err(EX_OSERR, "can't create node"); 14752419Sjulian 14852419Sjulian /* Do commands as requested */ 14952419Sjulian if (ac == 0) { 15052419Sjulian if (fp != NULL) { 15152419Sjulian rtn = ReadFile(fp); 15252419Sjulian } else if (interactive) { 15352419Sjulian rtn = DoInteractive(); 15452419Sjulian } else 15552419Sjulian Usage("no command specified"); 15652419Sjulian } else { 15752419Sjulian rtn = DoCommand(ac, av); 15852419Sjulian } 15952419Sjulian 16052419Sjulian /* Convert command return code into system exit code */ 16152419Sjulian switch (rtn) { 16252419Sjulian case CMDRTN_OK: 16352419Sjulian case CMDRTN_QUIT: 16452419Sjulian rtn = 0; 16552419Sjulian break; 16652419Sjulian case CMDRTN_USAGE: 16752419Sjulian rtn = EX_USAGE; 16852419Sjulian break; 16952419Sjulian case CMDRTN_ERROR: 17052419Sjulian rtn = EX_OSERR; 17152419Sjulian break; 17252419Sjulian } 17352419Sjulian return(rtn); 17452419Sjulian} 17552419Sjulian 17652419Sjulian/* 17752419Sjulian * Process commands from a file 17852419Sjulian */ 17952419Sjulianstatic int 18052419SjulianReadFile(FILE *fp) 18152419Sjulian{ 18252419Sjulian char line[LINE_MAX]; 18352419Sjulian int num, rtn; 18452419Sjulian 18552419Sjulian for (num = 1; fgets(line, sizeof(line), fp) != NULL; num++) { 18652419Sjulian if (*line == '#') 18752419Sjulian continue; 18852419Sjulian if ((rtn = DoParseCommand(line)) != 0) { 18952419Sjulian warnx("line %d: error in file", num); 19052419Sjulian return(rtn); 19152419Sjulian } 19252419Sjulian } 19352419Sjulian return(CMDRTN_OK); 19452419Sjulian} 19552419Sjulian 19652419Sjulian/* 19752419Sjulian * Interactive mode 19852419Sjulian */ 19952419Sjulianstatic int 20052419SjulianDoInteractive(void) 20152419Sjulian{ 20253913Sarchie const int maxfd = MAX(csock, dsock) + 1; 20352419Sjulian 20452419Sjulian (*help_cmd.func)(0, NULL); 20553913Sarchie while (1) { 20653913Sarchie struct timeval tv; 20753913Sarchie fd_set rfds; 20853913Sarchie 20953913Sarchie /* See if any data or control messages are arriving */ 21053913Sarchie FD_ZERO(&rfds); 21153913Sarchie FD_SET(csock, &rfds); 21253913Sarchie FD_SET(dsock, &rfds); 21353913Sarchie memset(&tv, 0, sizeof(tv)); 21453913Sarchie if (select(maxfd, &rfds, NULL, NULL, &tv) <= 0) { 21553913Sarchie 21653913Sarchie /* Issue prompt and wait for anything to happen */ 21753913Sarchie printf("%s", PROMPT); 21853913Sarchie fflush(stdout); 21953913Sarchie FD_ZERO(&rfds); 22053913Sarchie FD_SET(0, &rfds); 22153913Sarchie FD_SET(csock, &rfds); 22253913Sarchie FD_SET(dsock, &rfds); 22353913Sarchie if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) 22453913Sarchie err(EX_OSERR, "select"); 22553913Sarchie 22653913Sarchie /* If not user input, print a newline first */ 22753913Sarchie if (!FD_ISSET(0, &rfds)) 22853913Sarchie printf("\n"); 22953913Sarchie } 23053913Sarchie 23153913Sarchie /* Display any incoming control message */ 23261880Sarchie if (FD_ISSET(csock, &rfds)) 23361880Sarchie MsgRead(); 23453913Sarchie 23553913Sarchie /* Display any incoming data packet */ 23661880Sarchie if (FD_ISSET(dsock, &rfds)) { 23753913Sarchie u_char buf[8192]; 23853913Sarchie char hook[NG_HOOKLEN + 1]; 23953913Sarchie int rl; 24053913Sarchie 24153913Sarchie /* Read packet from socket */ 24253913Sarchie if ((rl = NgRecvData(dsock, 24353913Sarchie buf, sizeof(buf), hook)) < 0) 24461880Sarchie err(EX_OSERR, "reading hook \"%s\"", hook); 24553913Sarchie if (rl == 0) 24653913Sarchie errx(EX_OSERR, "EOF from hook \"%s\"?", hook); 24753913Sarchie 24853913Sarchie /* Write packet to stdout */ 24953913Sarchie printf("Rec'd data packet on hook \"%s\":\n", hook); 25053913Sarchie DumpAscii(buf, rl); 25153913Sarchie } 25253913Sarchie 25353913Sarchie /* Get any user input */ 25453913Sarchie if (FD_ISSET(0, &rfds)) { 25553913Sarchie char buf[LINE_MAX]; 25653913Sarchie 25753913Sarchie if (fgets(buf, sizeof(buf), stdin) == NULL) { 25853913Sarchie printf("\n"); 25953913Sarchie break; 26053913Sarchie } 26153913Sarchie if (DoParseCommand(buf) == CMDRTN_QUIT) 26253913Sarchie break; 26353913Sarchie } 26453913Sarchie } 26552419Sjulian return(CMDRTN_QUIT); 26652419Sjulian} 26752419Sjulian 26852419Sjulian/* 26952419Sjulian * Parse a command line and execute the command 27052419Sjulian */ 27152419Sjulianstatic int 27252419SjulianDoParseCommand(char *line) 27352419Sjulian{ 27452419Sjulian char *av[MAX_ARGS]; 27552419Sjulian int ac; 27652419Sjulian 27752419Sjulian /* Parse line */ 27852419Sjulian for (ac = 0, av[0] = strtok(line, WHITESPACE); 27952419Sjulian ac < MAX_ARGS - 1 && av[ac]; 28052419Sjulian av[++ac] = strtok(NULL, WHITESPACE)); 28152419Sjulian 28252419Sjulian /* Do command */ 28352419Sjulian return(DoCommand(ac, av)); 28452419Sjulian} 28552419Sjulian 28652419Sjulian/* 28752419Sjulian * Execute the command 28852419Sjulian */ 28952419Sjulianstatic int 29052419SjulianDoCommand(int ac, char **av) 29152419Sjulian{ 29252419Sjulian const struct ngcmd *cmd; 29352419Sjulian int rtn; 29452419Sjulian 29552419Sjulian if (ac == 0 || *av[0] == 0) 29652419Sjulian return(CMDRTN_OK); 29752419Sjulian if ((cmd = FindCommand(av[0])) == NULL) 29852419Sjulian return(CMDRTN_ERROR); 29952419Sjulian if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE) 30052419Sjulian warnx("usage: %s", cmd->cmd); 30152419Sjulian return(rtn); 30252419Sjulian} 30352419Sjulian 30452419Sjulian/* 30552419Sjulian * Find a command 30652419Sjulian */ 30752419Sjulianstatic const struct ngcmd * 30852419SjulianFindCommand(const char *string) 30952419Sjulian{ 31053913Sarchie int k, found = -1; 31152419Sjulian 31253913Sarchie for (k = 0; cmds[k] != NULL; k++) { 31353913Sarchie if (MatchCommand(cmds[k], string)) { 31452419Sjulian if (found != -1) { 31552419Sjulian warnx("\"%s\": ambiguous command", string); 31652419Sjulian return(NULL); 31752419Sjulian } 31852419Sjulian found = k; 31952419Sjulian } 32052419Sjulian } 32152419Sjulian if (found == -1) { 32252419Sjulian warnx("\"%s\": unknown command", string); 32352419Sjulian return(NULL); 32452419Sjulian } 32552419Sjulian return(cmds[found]); 32652419Sjulian} 32752419Sjulian 32852419Sjulian/* 32953913Sarchie * See if string matches a prefix of "cmd" (or an alias) case insensitively 33053913Sarchie */ 33153913Sarchiestatic int 33253913SarchieMatchCommand(const struct ngcmd *cmd, const char *s) 33353913Sarchie{ 33453913Sarchie int a; 33553913Sarchie 33653913Sarchie /* Try to match command, ignoring the usage stuff */ 33753913Sarchie if (strlen(s) <= strcspn(cmd->cmd, WHITESPACE)) { 33853913Sarchie if (strncasecmp(s, cmd->cmd, strlen(s)) == 0) 33953913Sarchie return (1); 34053913Sarchie } 34153913Sarchie 34253913Sarchie /* Try to match aliases */ 34353913Sarchie for (a = 0; a < MAX_CMD_ALIAS && cmd->aliases[a] != NULL; a++) { 34453913Sarchie if (strlen(cmd->aliases[a]) >= strlen(s)) { 34553913Sarchie if (strncasecmp(s, cmd->aliases[a], strlen(s)) == 0) 34653913Sarchie return (1); 34753913Sarchie } 34853913Sarchie } 34953913Sarchie 35053913Sarchie /* No match */ 35153913Sarchie return (0); 35253913Sarchie} 35353913Sarchie 35453913Sarchie/* 35552419Sjulian * ReadCmd() 35652419Sjulian */ 35752419Sjulianstatic int 35852419SjulianReadCmd(int ac, char **av) 35952419Sjulian{ 36052419Sjulian FILE *fp; 36152419Sjulian int rtn; 36252419Sjulian 36352419Sjulian /* Open file */ 36452419Sjulian switch (ac) { 36552419Sjulian case 2: 36666904Sarchie if ((fp = fopen(av[1], "r")) == NULL) { 36752419Sjulian warn("%s", av[1]); 36866904Sarchie return(CMDRTN_ERROR); 36966904Sarchie } 37066904Sarchie break; 37152419Sjulian default: 37252419Sjulian return(CMDRTN_USAGE); 37352419Sjulian } 37452419Sjulian 37552419Sjulian /* Process it */ 37652419Sjulian rtn = ReadFile(fp); 37752419Sjulian fclose(fp); 37852419Sjulian return(rtn); 37952419Sjulian} 38052419Sjulian 38152419Sjulian/* 38252419Sjulian * HelpCmd() 38352419Sjulian */ 38452419Sjulianstatic int 38552419SjulianHelpCmd(int ac, char **av) 38652419Sjulian{ 38752419Sjulian const struct ngcmd *cmd; 38852419Sjulian int k; 38952419Sjulian 39052419Sjulian switch (ac) { 39152419Sjulian case 0: 39252419Sjulian case 1: 39352419Sjulian /* Show all commands */ 39452419Sjulian printf("Available commands:\n"); 39552419Sjulian for (k = 0; cmds[k] != NULL; k++) { 39652419Sjulian char *s, buf[100]; 39752419Sjulian 39852419Sjulian cmd = cmds[k]; 39952419Sjulian snprintf(buf, sizeof(buf), "%s", cmd->cmd); 40052419Sjulian for (s = buf; *s != '\0' && !isspace(*s); s++); 40152419Sjulian *s = '\0'; 40252419Sjulian printf(" %-10s %s\n", buf, cmd->desc); 40352419Sjulian } 40452419Sjulian return(CMDRTN_OK); 40552419Sjulian default: 40652419Sjulian /* Show help on a specific command */ 40752419Sjulian if ((cmd = FindCommand(av[1])) != NULL) { 40852419Sjulian printf("Usage: %s\n", cmd->cmd); 40953913Sarchie if (cmd->aliases[0] != NULL) { 41053913Sarchie int a = 0; 41153913Sarchie 41253913Sarchie printf("Aliases: "); 41353913Sarchie while (1) { 41453913Sarchie printf("%s", cmd->aliases[a++]); 41553913Sarchie if (a == MAX_CMD_ALIAS 41653913Sarchie || cmd->aliases[a] == NULL) { 41753913Sarchie printf("\n"); 41853913Sarchie break; 41953913Sarchie } 42053913Sarchie printf(", "); 42153913Sarchie } 42253913Sarchie } 42352419Sjulian printf("Summary: %s\n", cmd->desc); 42452419Sjulian if (cmd->help != NULL) { 42552419Sjulian const char *s; 42652419Sjulian char buf[65]; 42752419Sjulian int tot, len, done; 42852419Sjulian 42952419Sjulian printf("Description:\n"); 43052419Sjulian for (s = cmd->help; *s != '\0'; s += len) { 43152419Sjulian while (isspace(*s)) 43252419Sjulian s++; 43352419Sjulian tot = snprintf(buf, 43452419Sjulian sizeof(buf), "%s", s); 43552419Sjulian len = strlen(buf); 43652419Sjulian done = len == tot; 43752419Sjulian if (!done) { 43852419Sjulian while (len > 0 43952419Sjulian && !isspace(buf[len-1])) 44052419Sjulian buf[--len] = '\0'; 44152419Sjulian } 44252419Sjulian printf(" %s\n", buf); 44352419Sjulian } 44452419Sjulian } 44552419Sjulian } 44652419Sjulian } 44752419Sjulian return(CMDRTN_OK); 44852419Sjulian} 44952419Sjulian 45052419Sjulian/* 45152419Sjulian * QuitCmd() 45252419Sjulian */ 45352419Sjulianstatic int 45452419SjulianQuitCmd(int ac, char **av) 45552419Sjulian{ 45652419Sjulian return(CMDRTN_QUIT); 45752419Sjulian} 45852419Sjulian 45952419Sjulian/* 46053913Sarchie * Dump data in hex and ASCII form 46153913Sarchie */ 46261880Sarchievoid 46353913SarchieDumpAscii(const u_char *buf, int len) 46453913Sarchie{ 46553913Sarchie char ch, sbuf[100]; 46653913Sarchie int k, count; 46753913Sarchie 46853913Sarchie for (count = 0; count < len; count += DUMP_BYTES_PER_LINE) { 46953913Sarchie snprintf(sbuf, sizeof(sbuf), "%04x: ", count); 47053913Sarchie for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 47153913Sarchie if (count + k < len) { 47253913Sarchie snprintf(sbuf + strlen(sbuf), 47353913Sarchie sizeof(sbuf) - strlen(sbuf), 47453913Sarchie "%02x ", buf[count + k]); 47553913Sarchie } else { 47653913Sarchie snprintf(sbuf + strlen(sbuf), 47753913Sarchie sizeof(sbuf) - strlen(sbuf), " "); 47853913Sarchie } 47953913Sarchie } 48053913Sarchie snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " "); 48153913Sarchie for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 48253913Sarchie if (count + k < len) { 48353913Sarchie ch = isprint(buf[count + k]) ? 48453913Sarchie buf[count + k] : '.'; 48553913Sarchie snprintf(sbuf + strlen(sbuf), 48653913Sarchie sizeof(sbuf) - strlen(sbuf), "%c", ch); 48753913Sarchie } else { 48853913Sarchie snprintf(sbuf + strlen(sbuf), 48953913Sarchie sizeof(sbuf) - strlen(sbuf), " "); 49053913Sarchie } 49153913Sarchie } 49253913Sarchie printf("%s\n", sbuf); 49353913Sarchie } 49453913Sarchie} 49553913Sarchie 49653913Sarchie/* 49752419Sjulian * Usage() 49852419Sjulian */ 49952419Sjulianstatic void 50052419SjulianUsage(const char *msg) 50152419Sjulian{ 50252419Sjulian if (msg) 50352419Sjulian warnx("%s", msg); 50452419Sjulian errx(EX_USAGE, "usage: ngctl [-d] [-f file] [-n name] [command ...]"); 50552419Sjulian} 50652419Sjulian 507