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