main.c revision 124130
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 124130 2004-01-04 16:11:29Z charnier $ 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, 7689674Sarchie &write_cmd, 7752419Sjulian &quit_cmd, 7852419Sjulian NULL 7952419Sjulian}; 8052419Sjulian 8152419Sjulian/* Commands defined in this file */ 8252419Sjulianconst struct ngcmd read_cmd = { 8352419Sjulian ReadCmd, 8452419Sjulian "read <filename>", 8552419Sjulian "Read and execute commands from a file", 8653913Sarchie NULL, 8753913Sarchie { "source", "." } 8852419Sjulian}; 8952419Sjulianconst struct ngcmd help_cmd = { 9052419Sjulian HelpCmd, 9152419Sjulian "help [command]", 9252419Sjulian "Show command summary or get more help on a specific command", 9353913Sarchie NULL, 9453913Sarchie { "?" } 9552419Sjulian}; 9652419Sjulianconst struct ngcmd quit_cmd = { 9752419Sjulian QuitCmd, 9852419Sjulian "quit", 9952419Sjulian "Exit program", 10053913Sarchie NULL, 10153913Sarchie { "exit" } 10252419Sjulian}; 10352419Sjulian 10452419Sjulian/* Our control and data sockets */ 10552419Sjulianint csock, dsock; 10652419Sjulian 10752419Sjulian/* 10852419Sjulian * main() 10952419Sjulian */ 11052419Sjulianint 11152419Sjulianmain(int ac, char *av[]) 11252419Sjulian{ 113122556Sharti char name[NG_NODESIZ]; 11452419Sjulian int interactive = isatty(0) && isatty(1); 11552419Sjulian FILE *fp = NULL; 11652419Sjulian int ch, rtn = 0; 11752419Sjulian 11852419Sjulian /* Set default node name */ 11952419Sjulian snprintf(name, sizeof(name), "ngctl%d", getpid()); 12052419Sjulian 12152419Sjulian /* Parse command line */ 12252419Sjulian while ((ch = getopt(ac, av, "df:n:")) != EOF) { 12352419Sjulian switch (ch) { 12452419Sjulian case 'd': 12552419Sjulian NgSetDebug(NgSetDebug(-1) + 1); 12652419Sjulian break; 12752419Sjulian case 'f': 12852419Sjulian if (strcmp(optarg, "-") == 0) 12952419Sjulian fp = stdin; 13052419Sjulian else if ((fp = fopen(optarg, "r")) == NULL) 13152419Sjulian err(EX_NOINPUT, "%s", optarg); 13252419Sjulian break; 13352419Sjulian case 'n': 13452419Sjulian snprintf(name, sizeof(name), "%s", optarg); 13552419Sjulian break; 13652419Sjulian case '?': 13752419Sjulian default: 13852419Sjulian Usage((char *)NULL); 13952419Sjulian break; 14052419Sjulian } 14152419Sjulian } 14252419Sjulian ac -= optind; 14352419Sjulian av += optind; 14452419Sjulian 14552419Sjulian /* Create a new socket node */ 14656709Sarchie if (NgMkSockNode(name, &csock, &dsock) < 0) 14752419Sjulian err(EX_OSERR, "can't create node"); 14852419Sjulian 14952419Sjulian /* Do commands as requested */ 15052419Sjulian if (ac == 0) { 15152419Sjulian if (fp != NULL) { 15252419Sjulian rtn = ReadFile(fp); 15352419Sjulian } else if (interactive) { 15452419Sjulian rtn = DoInteractive(); 15552419Sjulian } else 15652419Sjulian Usage("no command specified"); 15752419Sjulian } else { 15852419Sjulian rtn = DoCommand(ac, av); 15952419Sjulian } 16052419Sjulian 16152419Sjulian /* Convert command return code into system exit code */ 16252419Sjulian switch (rtn) { 16352419Sjulian case CMDRTN_OK: 16452419Sjulian case CMDRTN_QUIT: 16552419Sjulian rtn = 0; 16652419Sjulian break; 16752419Sjulian case CMDRTN_USAGE: 16852419Sjulian rtn = EX_USAGE; 16952419Sjulian break; 17052419Sjulian case CMDRTN_ERROR: 17152419Sjulian rtn = EX_OSERR; 17252419Sjulian break; 17352419Sjulian } 17452419Sjulian return(rtn); 17552419Sjulian} 17652419Sjulian 17752419Sjulian/* 17852419Sjulian * Process commands from a file 17952419Sjulian */ 18052419Sjulianstatic int 18152419SjulianReadFile(FILE *fp) 18252419Sjulian{ 18352419Sjulian char line[LINE_MAX]; 18452419Sjulian int num, rtn; 18552419Sjulian 18652419Sjulian for (num = 1; fgets(line, sizeof(line), fp) != NULL; num++) { 18752419Sjulian if (*line == '#') 18852419Sjulian continue; 18952419Sjulian if ((rtn = DoParseCommand(line)) != 0) { 19052419Sjulian warnx("line %d: error in file", num); 19152419Sjulian return(rtn); 19252419Sjulian } 19352419Sjulian } 19452419Sjulian return(CMDRTN_OK); 19552419Sjulian} 19652419Sjulian 19752419Sjulian/* 19852419Sjulian * Interactive mode 19952419Sjulian */ 20052419Sjulianstatic int 20152419SjulianDoInteractive(void) 20252419Sjulian{ 20353913Sarchie const int maxfd = MAX(csock, dsock) + 1; 20452419Sjulian 20552419Sjulian (*help_cmd.func)(0, NULL); 20653913Sarchie while (1) { 20753913Sarchie struct timeval tv; 20853913Sarchie fd_set rfds; 20953913Sarchie 21053913Sarchie /* See if any data or control messages are arriving */ 21153913Sarchie FD_ZERO(&rfds); 21253913Sarchie FD_SET(csock, &rfds); 21353913Sarchie FD_SET(dsock, &rfds); 21453913Sarchie memset(&tv, 0, sizeof(tv)); 21553913Sarchie if (select(maxfd, &rfds, NULL, NULL, &tv) <= 0) { 21653913Sarchie 21753913Sarchie /* Issue prompt and wait for anything to happen */ 21853913Sarchie printf("%s", PROMPT); 21953913Sarchie fflush(stdout); 22053913Sarchie FD_ZERO(&rfds); 22153913Sarchie FD_SET(0, &rfds); 22253913Sarchie FD_SET(csock, &rfds); 22353913Sarchie FD_SET(dsock, &rfds); 22453913Sarchie if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) 22553913Sarchie err(EX_OSERR, "select"); 22653913Sarchie 22753913Sarchie /* If not user input, print a newline first */ 22853913Sarchie if (!FD_ISSET(0, &rfds)) 22953913Sarchie printf("\n"); 23053913Sarchie } 23153913Sarchie 23253913Sarchie /* Display any incoming control message */ 23361880Sarchie if (FD_ISSET(csock, &rfds)) 23461880Sarchie MsgRead(); 23553913Sarchie 23653913Sarchie /* Display any incoming data packet */ 23761880Sarchie if (FD_ISSET(dsock, &rfds)) { 23853913Sarchie u_char buf[8192]; 239122556Sharti char hook[NG_HOOKSIZ]; 24053913Sarchie int rl; 24153913Sarchie 24253913Sarchie /* Read packet from socket */ 24353913Sarchie if ((rl = NgRecvData(dsock, 24453913Sarchie buf, sizeof(buf), hook)) < 0) 24561880Sarchie err(EX_OSERR, "reading hook \"%s\"", hook); 24653913Sarchie if (rl == 0) 24753913Sarchie errx(EX_OSERR, "EOF from hook \"%s\"?", hook); 24853913Sarchie 24953913Sarchie /* Write packet to stdout */ 25053913Sarchie printf("Rec'd data packet on hook \"%s\":\n", hook); 25153913Sarchie DumpAscii(buf, rl); 25253913Sarchie } 25353913Sarchie 25453913Sarchie /* Get any user input */ 25553913Sarchie if (FD_ISSET(0, &rfds)) { 25674383Sphk char buf[LINE_MAX]; 25774383Sphk 25874383Sphk if (fgets(buf, sizeof(buf), stdin) == NULL) { 25974383Sphk printf("\n"); 26053913Sarchie break; 26174383Sphk } 26274383Sphk if (DoParseCommand(buf) == CMDRTN_QUIT) 26374383Sphk break; 26453913Sarchie } 26553913Sarchie } 26652419Sjulian return(CMDRTN_QUIT); 26752419Sjulian} 26852419Sjulian 26952419Sjulian/* 27052419Sjulian * Parse a command line and execute the command 27152419Sjulian */ 27252419Sjulianstatic int 27352419SjulianDoParseCommand(char *line) 27452419Sjulian{ 27552419Sjulian char *av[MAX_ARGS]; 27652419Sjulian int ac; 27752419Sjulian 27852419Sjulian /* Parse line */ 27952419Sjulian for (ac = 0, av[0] = strtok(line, WHITESPACE); 28052419Sjulian ac < MAX_ARGS - 1 && av[ac]; 28152419Sjulian av[++ac] = strtok(NULL, WHITESPACE)); 28252419Sjulian 28352419Sjulian /* Do command */ 28452419Sjulian return(DoCommand(ac, av)); 28552419Sjulian} 28652419Sjulian 28752419Sjulian/* 28852419Sjulian * Execute the command 28952419Sjulian */ 29052419Sjulianstatic int 29152419SjulianDoCommand(int ac, char **av) 29252419Sjulian{ 29352419Sjulian const struct ngcmd *cmd; 29452419Sjulian int rtn; 29552419Sjulian 29652419Sjulian if (ac == 0 || *av[0] == 0) 29752419Sjulian return(CMDRTN_OK); 29852419Sjulian if ((cmd = FindCommand(av[0])) == NULL) 29952419Sjulian return(CMDRTN_ERROR); 30052419Sjulian if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE) 30152419Sjulian warnx("usage: %s", cmd->cmd); 30252419Sjulian return(rtn); 30352419Sjulian} 30452419Sjulian 30552419Sjulian/* 30652419Sjulian * Find a command 30752419Sjulian */ 30852419Sjulianstatic const struct ngcmd * 30952419SjulianFindCommand(const char *string) 31052419Sjulian{ 31153913Sarchie int k, found = -1; 31252419Sjulian 31353913Sarchie for (k = 0; cmds[k] != NULL; k++) { 31453913Sarchie if (MatchCommand(cmds[k], string)) { 31552419Sjulian if (found != -1) { 31652419Sjulian warnx("\"%s\": ambiguous command", string); 31752419Sjulian return(NULL); 31852419Sjulian } 31952419Sjulian found = k; 32052419Sjulian } 32152419Sjulian } 32252419Sjulian if (found == -1) { 32352419Sjulian warnx("\"%s\": unknown command", string); 32452419Sjulian return(NULL); 32552419Sjulian } 32652419Sjulian return(cmds[found]); 32752419Sjulian} 32852419Sjulian 32952419Sjulian/* 33053913Sarchie * See if string matches a prefix of "cmd" (or an alias) case insensitively 33153913Sarchie */ 33253913Sarchiestatic int 33353913SarchieMatchCommand(const struct ngcmd *cmd, const char *s) 33453913Sarchie{ 33553913Sarchie int a; 33653913Sarchie 33753913Sarchie /* Try to match command, ignoring the usage stuff */ 33853913Sarchie if (strlen(s) <= strcspn(cmd->cmd, WHITESPACE)) { 33953913Sarchie if (strncasecmp(s, cmd->cmd, strlen(s)) == 0) 34053913Sarchie return (1); 34153913Sarchie } 34253913Sarchie 34353913Sarchie /* Try to match aliases */ 34453913Sarchie for (a = 0; a < MAX_CMD_ALIAS && cmd->aliases[a] != NULL; a++) { 34553913Sarchie if (strlen(cmd->aliases[a]) >= strlen(s)) { 34653913Sarchie if (strncasecmp(s, cmd->aliases[a], strlen(s)) == 0) 34753913Sarchie return (1); 34853913Sarchie } 34953913Sarchie } 35053913Sarchie 35153913Sarchie /* No match */ 35253913Sarchie return (0); 35353913Sarchie} 35453913Sarchie 35553913Sarchie/* 35652419Sjulian * ReadCmd() 35752419Sjulian */ 35852419Sjulianstatic int 35952419SjulianReadCmd(int ac, char **av) 36052419Sjulian{ 36152419Sjulian FILE *fp; 36252419Sjulian int rtn; 36352419Sjulian 36452419Sjulian /* Open file */ 36552419Sjulian switch (ac) { 36652419Sjulian case 2: 36766904Sarchie if ((fp = fopen(av[1], "r")) == NULL) { 36852419Sjulian warn("%s", av[1]); 36966904Sarchie return(CMDRTN_ERROR); 37066904Sarchie } 37166904Sarchie break; 37252419Sjulian default: 37352419Sjulian return(CMDRTN_USAGE); 37452419Sjulian } 37552419Sjulian 37652419Sjulian /* Process it */ 37752419Sjulian rtn = ReadFile(fp); 37852419Sjulian fclose(fp); 37952419Sjulian return(rtn); 38052419Sjulian} 38152419Sjulian 38252419Sjulian/* 38352419Sjulian * HelpCmd() 38452419Sjulian */ 38552419Sjulianstatic int 38652419SjulianHelpCmd(int ac, char **av) 38752419Sjulian{ 38852419Sjulian const struct ngcmd *cmd; 38952419Sjulian int k; 39052419Sjulian 39152419Sjulian switch (ac) { 39252419Sjulian case 0: 39352419Sjulian case 1: 39452419Sjulian /* Show all commands */ 39552419Sjulian printf("Available commands:\n"); 39652419Sjulian for (k = 0; cmds[k] != NULL; k++) { 39752419Sjulian char *s, buf[100]; 39852419Sjulian 39952419Sjulian cmd = cmds[k]; 40052419Sjulian snprintf(buf, sizeof(buf), "%s", cmd->cmd); 40152419Sjulian for (s = buf; *s != '\0' && !isspace(*s); s++); 40252419Sjulian *s = '\0'; 40352419Sjulian printf(" %-10s %s\n", buf, cmd->desc); 40452419Sjulian } 40552419Sjulian return(CMDRTN_OK); 40652419Sjulian default: 40752419Sjulian /* Show help on a specific command */ 40852419Sjulian if ((cmd = FindCommand(av[1])) != NULL) { 40995258Sdes printf("usage: %s\n", cmd->cmd); 41053913Sarchie if (cmd->aliases[0] != NULL) { 41153913Sarchie int a = 0; 41253913Sarchie 41353913Sarchie printf("Aliases: "); 41453913Sarchie while (1) { 41553913Sarchie printf("%s", cmd->aliases[a++]); 41653913Sarchie if (a == MAX_CMD_ALIAS 41753913Sarchie || cmd->aliases[a] == NULL) { 41853913Sarchie printf("\n"); 41953913Sarchie break; 42053913Sarchie } 42153913Sarchie printf(", "); 42253913Sarchie } 42353913Sarchie } 42452419Sjulian printf("Summary: %s\n", cmd->desc); 42552419Sjulian if (cmd->help != NULL) { 42652419Sjulian const char *s; 42752419Sjulian char buf[65]; 42852419Sjulian int tot, len, done; 42952419Sjulian 43052419Sjulian printf("Description:\n"); 43152419Sjulian for (s = cmd->help; *s != '\0'; s += len) { 43252419Sjulian while (isspace(*s)) 43352419Sjulian s++; 43452419Sjulian tot = snprintf(buf, 43552419Sjulian sizeof(buf), "%s", s); 43652419Sjulian len = strlen(buf); 43752419Sjulian done = len == tot; 43852419Sjulian if (!done) { 43952419Sjulian while (len > 0 44052419Sjulian && !isspace(buf[len-1])) 44152419Sjulian buf[--len] = '\0'; 44252419Sjulian } 44352419Sjulian printf(" %s\n", buf); 44452419Sjulian } 44552419Sjulian } 44652419Sjulian } 44752419Sjulian } 44852419Sjulian return(CMDRTN_OK); 44952419Sjulian} 45052419Sjulian 45152419Sjulian/* 45252419Sjulian * QuitCmd() 45352419Sjulian */ 45452419Sjulianstatic int 45552419SjulianQuitCmd(int ac, char **av) 45652419Sjulian{ 45752419Sjulian return(CMDRTN_QUIT); 45852419Sjulian} 45952419Sjulian 46052419Sjulian/* 46153913Sarchie * Dump data in hex and ASCII form 46253913Sarchie */ 46361880Sarchievoid 46453913SarchieDumpAscii(const u_char *buf, int len) 46553913Sarchie{ 46653913Sarchie char ch, sbuf[100]; 46753913Sarchie int k, count; 46853913Sarchie 46953913Sarchie for (count = 0; count < len; count += DUMP_BYTES_PER_LINE) { 47053913Sarchie snprintf(sbuf, sizeof(sbuf), "%04x: ", count); 47153913Sarchie for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 47253913Sarchie if (count + k < len) { 47353913Sarchie snprintf(sbuf + strlen(sbuf), 47453913Sarchie sizeof(sbuf) - strlen(sbuf), 47553913Sarchie "%02x ", buf[count + k]); 47653913Sarchie } else { 47753913Sarchie snprintf(sbuf + strlen(sbuf), 47853913Sarchie sizeof(sbuf) - strlen(sbuf), " "); 47953913Sarchie } 48053913Sarchie } 48153913Sarchie snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " "); 48253913Sarchie for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 48353913Sarchie if (count + k < len) { 48453913Sarchie ch = isprint(buf[count + k]) ? 48553913Sarchie buf[count + k] : '.'; 48653913Sarchie snprintf(sbuf + strlen(sbuf), 48753913Sarchie sizeof(sbuf) - strlen(sbuf), "%c", ch); 48853913Sarchie } else { 48953913Sarchie snprintf(sbuf + strlen(sbuf), 49053913Sarchie sizeof(sbuf) - strlen(sbuf), " "); 49153913Sarchie } 49253913Sarchie } 49353913Sarchie printf("%s\n", sbuf); 49453913Sarchie } 49553913Sarchie} 49653913Sarchie 49753913Sarchie/* 49852419Sjulian * Usage() 49952419Sjulian */ 50052419Sjulianstatic void 50152419SjulianUsage(const char *msg) 50252419Sjulian{ 50352419Sjulian if (msg) 50452419Sjulian warnx("%s", msg); 505124130Scharnier fprintf(stderr, 506124130Scharnier "usage: ngctl [-d] [-f file] [-n name] [command ...]\n"); 507124130Scharnier exit(EX_USAGE); 50852419Sjulian} 509