main.c revision 138076
1155192Srwatson 2155192Srwatson/* 3155406Srwatson * main.c 4155192Srwatson * 5155192Srwatson * Copyright (c) 1996-1999 Whistle Communications, Inc. 6155192Srwatson * All rights reserved. 7155192Srwatson * 8155192Srwatson * Subject to the following obligations and disclaimer of warranty, use and 9155192Srwatson * redistribution of this software, in source or object code forms, with or 10155192Srwatson * without modifications are expressly permitted by Whistle Communications; 11155192Srwatson * provided, however, that: 12155192Srwatson * 1. Any and all reproductions of the source or object code must include the 13155192Srwatson * copyright notice above and the following disclaimer of warranties; and 14155192Srwatson * 2. No rights are granted, in any manner or form, to use Whistle 15155192Srwatson * Communications, Inc. trademarks, including the mark "WHISTLE 16155192Srwatson * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17155192Srwatson * such appears in the above copyright notice or in the software. 18155192Srwatson * 19155192Srwatson * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20155192Srwatson * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21155192Srwatson * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22155192Srwatson * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23155192Srwatson * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24155192Srwatson * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25155192Srwatson * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26155192Srwatson * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27155192Srwatson * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28155192Srwatson * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29155192Srwatson * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30155192Srwatson * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31155192Srwatson * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32155192Srwatson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33155192Srwatson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34155192Srwatson * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35155192Srwatson * OF SUCH DAMAGE. 36155192Srwatson * 37155192Srwatson * $FreeBSD: head/usr.sbin/ngctl/main.c 138076 2004-11-25 09:27:56Z maxim $ 38155192Srwatson * $Whistle: main.c,v 1.12 1999/11/29 19:17:46 archie Exp $ 39155192Srwatson */ 40155192Srwatson 41155192Srwatson#include "ngctl.h" 42155192Srwatson 43155192Srwatson#define PROMPT "+ " 44155192Srwatson#define MAX_ARGS 512 45164033Srwatson#define WHITESPACE " \t\r\n\v\f" 46155192Srwatson#define DUMP_BYTES_PER_LINE 16 47155192Srwatson 48155192Srwatson/* Internal functions */ 49155192Srwatsonstatic int ReadFile(FILE *fp); 50155192Srwatsonstatic int DoParseCommand(char *line); 51155192Srwatsonstatic int DoCommand(int ac, char **av); 52155192Srwatsonstatic int DoInteractive(void); 53155192Srwatsonstatic const struct ngcmd *FindCommand(const char *string); 54155192Srwatsonstatic int MatchCommand(const struct ngcmd *cmd, const char *s); 55155192Srwatsonstatic void Usage(const char *msg); 56155192Srwatsonstatic int ReadCmd(int ac, char **av); 57155192Srwatsonstatic int HelpCmd(int ac, char **av); 58155192Srwatsonstatic int QuitCmd(int ac, char **av); 59155192Srwatson 60155192Srwatson/* List of commands */ 61155406Srwatsonstatic const struct ngcmd *const cmds[] = { 62156291Srwatson &config_cmd, 63155406Srwatson &connect_cmd, 64155406Srwatson &debug_cmd, 65155192Srwatson &dot_cmd, 66155192Srwatson &help_cmd, 67155192Srwatson &list_cmd, 68155192Srwatson &mkpeer_cmd, 69155192Srwatson &msg_cmd, 70155192Srwatson &name_cmd, 71155406Srwatson &read_cmd, 72155406Srwatson &rmhook_cmd, 73156888Srwatson &show_cmd, 74155192Srwatson &shutdown_cmd, 75155192Srwatson &status_cmd, 76155192Srwatson &types_cmd, 77155192Srwatson &write_cmd, 78155192Srwatson &quit_cmd, 79155192Srwatson NULL 80156889Srwatson}; 81155192Srwatson 82155192Srwatson/* Commands defined in this file */ 83156889Srwatsonconst struct ngcmd read_cmd = { 84155192Srwatson ReadCmd, 85155192Srwatson "read <filename>", 86156889Srwatson "Read and execute commands from a file", 87156889Srwatson NULL, 88155192Srwatson { "source", "." } 89155192Srwatson}; 90162176Srwatsonconst struct ngcmd help_cmd = { 91162176Srwatson HelpCmd, 92155192Srwatson "help [command]", 93156889Srwatson "Show command summary or get more help on a specific command", 94156889Srwatson NULL, 95161813Swsalamon { "?" } 96161813Swsalamon}; 97155192Srwatsonconst struct ngcmd quit_cmd = { 98155192Srwatson QuitCmd, 99155192Srwatson "quit", 100155192Srwatson "Exit program", 101156889Srwatson NULL, 102155192Srwatson { "exit" } 103155192Srwatson}; 104156889Srwatson 105155192Srwatson/* Our control and data sockets */ 106156889Srwatsonint csock, dsock; 107155192Srwatson 108155192Srwatson/* 109155192Srwatson * main() 110155192Srwatson */ 111156889Srwatsonint 112155192Srwatsonmain(int ac, char *av[]) 113155192Srwatson{ 114155192Srwatson char name[NG_NODESIZ]; 115155192Srwatson int interactive = isatty(0) && isatty(1); 116155192Srwatson FILE *fp = NULL; 117156889Srwatson int ch, size, rtn = 0; 118155192Srwatson 119155192Srwatson /* Set default node name */ 120155192Srwatson snprintf(name, sizeof(name), "ngctl%d", getpid()); 121155192Srwatson 122155192Srwatson /* Parse command line */ 123155192Srwatson while ((ch = getopt(ac, av, "df:n:")) != EOF) { 124155192Srwatson switch (ch) { 125155192Srwatson case 'd': 126155192Srwatson NgSetDebug(NgSetDebug(-1) + 1); 127156889Srwatson break; 128156889Srwatson case 'f': 129156889Srwatson if (strcmp(optarg, "-") == 0) 130155192Srwatson fp = stdin; 131155192Srwatson else if ((fp = fopen(optarg, "r")) == NULL) 132155192Srwatson err(EX_NOINPUT, "%s", optarg); 133155192Srwatson break; 134156889Srwatson case 'n': 135155192Srwatson snprintf(name, sizeof(name), "%s", optarg); 136155192Srwatson break; 137155192Srwatson case '?': 138155192Srwatson default: 139155192Srwatson Usage((char *)NULL); 140155192Srwatson break; 141159261Srwatson } 142155192Srwatson } 143155192Srwatson ac -= optind; 144159261Srwatson av += optind; 145159261Srwatson 146159261Srwatson /* Create a new socket node */ 147155192Srwatson if (NgMkSockNode(name, &csock, &dsock) < 0) 148159261Srwatson err(EX_OSERR, "can't create node"); 149155192Srwatson size = 128 * 1024; 150156889Srwatson if (setsockopt(csock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) == -1) 151156889Srwatson err(1, "setsockopt"); 152156889Srwatson /* Do commands as requested */ 153155192Srwatson if (ac == 0) { 154155192Srwatson if (fp != NULL) { 155156889Srwatson rtn = ReadFile(fp); 156155192Srwatson } else if (interactive) { 157155192Srwatson rtn = DoInteractive(); 158155406Srwatson } else 159155192Srwatson Usage("no command specified"); 160155406Srwatson } else { 161155406Srwatson rtn = DoCommand(ac, av); 162155406Srwatson } 163155406Srwatson 164155406Srwatson /* Convert command return code into system exit code */ 165155406Srwatson switch (rtn) { 166155406Srwatson case CMDRTN_OK: 167155406Srwatson case CMDRTN_QUIT: 168155406Srwatson rtn = 0; 169155406Srwatson break; 170155406Srwatson case CMDRTN_USAGE: 171155406Srwatson rtn = EX_USAGE; 172155406Srwatson break; 173155406Srwatson case CMDRTN_ERROR: 174155406Srwatson rtn = EX_OSERR; 175155406Srwatson break; 176155406Srwatson } 177155406Srwatson return(rtn); 178155406Srwatson} 179155406Srwatson 180155406Srwatson/* 181159415Srwatson * Process commands from a file 182155406Srwatson */ 183155406Srwatsonstatic int 184155406SrwatsonReadFile(FILE *fp) 185155406Srwatson{ 186155406Srwatson char line[LINE_MAX]; 187155406Srwatson int num, rtn; 188159415Srwatson 189155406Srwatson for (num = 1; fgets(line, sizeof(line), fp) != NULL; num++) { 190155406Srwatson if (*line == '#') 191155406Srwatson continue; 192155406Srwatson if ((rtn = DoParseCommand(line)) != 0) { 193155192Srwatson warnx("line %d: error in file", num); 194155406Srwatson return(rtn); 195155192Srwatson } 196155406Srwatson } 197155192Srwatson return(CMDRTN_OK); 198155406Srwatson} 199155406Srwatson 200155406Srwatson/* 201155406Srwatson * Interactive mode 202155192Srwatson */ 203155406Srwatsonstatic int 204155192SrwatsonDoInteractive(void) 205155406Srwatson{ 206155192Srwatson const int maxfd = MAX(csock, dsock) + 1; 207155406Srwatson 208155192Srwatson (*help_cmd.func)(0, NULL); 209161813Swsalamon while (1) { 210161813Swsalamon struct timeval tv; 211161813Swsalamon fd_set rfds; 212161813Swsalamon 213155192Srwatson /* See if any data or control messages are arriving */ 214155192Srwatson FD_ZERO(&rfds); 215155192Srwatson FD_SET(csock, &rfds); 216155192Srwatson FD_SET(dsock, &rfds); 217155192Srwatson memset(&tv, 0, sizeof(tv)); 218155192Srwatson if (select(maxfd, &rfds, NULL, NULL, &tv) <= 0) { 219155192Srwatson 220155192Srwatson /* Issue prompt and wait for anything to happen */ 221155192Srwatson printf("%s", PROMPT); 222155192Srwatson fflush(stdout); 223155192Srwatson FD_ZERO(&rfds); 224155192Srwatson FD_SET(0, &rfds); 225155192Srwatson FD_SET(csock, &rfds); 226155192Srwatson FD_SET(dsock, &rfds); 227155192Srwatson if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) 228155192Srwatson err(EX_OSERR, "select"); 229155192Srwatson 230161813Swsalamon /* If not user input, print a newline first */ 231161813Swsalamon if (!FD_ISSET(0, &rfds)) 232155192Srwatson printf("\n"); 233155192Srwatson } 234156889Srwatson 235155192Srwatson /* Display any incoming control message */ 236155192Srwatson if (FD_ISSET(csock, &rfds)) 237155192Srwatson MsgRead(); 238155192Srwatson 239155192Srwatson /* Display any incoming data packet */ 240155192Srwatson if (FD_ISSET(dsock, &rfds)) { 241155192Srwatson u_char *buf; 242155192Srwatson char hook[NG_HOOKSIZ]; 243155192Srwatson int rl; 244155192Srwatson 245155192Srwatson /* Read packet from socket */ 246155192Srwatson if ((rl = NgAllocRecvData(dsock, &buf, hook)) < 0) 247159261Srwatson err(EX_OSERR, "reading hook \"%s\"", hook); 248159261Srwatson if (rl == 0) 249155192Srwatson errx(EX_OSERR, "EOF from hook \"%s\"?", hook); 250155192Srwatson 251159266Srwatson /* Write packet to stdout */ 252155406Srwatson printf("Rec'd data packet on hook \"%s\":\n", hook); 253155406Srwatson DumpAscii(buf, rl); 254155406Srwatson free(buf); 255155192Srwatson } 256155192Srwatson 257155192Srwatson /* Get any user input */ 258155192Srwatson if (FD_ISSET(0, &rfds)) { 259155192Srwatson char buf[LINE_MAX]; 260155192Srwatson 261155192Srwatson if (fgets(buf, sizeof(buf), stdin) == NULL) { 262155192Srwatson printf("\n"); 263155192Srwatson break; 264156888Srwatson } 265156888Srwatson if (DoParseCommand(buf) == CMDRTN_QUIT) 266155192Srwatson break; 267155192Srwatson } 268155192Srwatson } 269155192Srwatson return(CMDRTN_QUIT); 270155192Srwatson} 271155192Srwatson 272155192Srwatson/* 273155192Srwatson * Parse a command line and execute the command 274155192Srwatson */ 275155192Srwatsonstatic int 276155192SrwatsonDoParseCommand(char *line) 277155192Srwatson{ 278155192Srwatson char *av[MAX_ARGS]; 279155192Srwatson int ac; 280155192Srwatson 281155192Srwatson /* Parse line */ 282155192Srwatson for (ac = 0, av[0] = strtok(line, WHITESPACE); 283155192Srwatson ac < MAX_ARGS - 1 && av[ac]; 284155192Srwatson av[++ac] = strtok(NULL, WHITESPACE)); 285155192Srwatson 286155192Srwatson /* Do command */ 287155192Srwatson return(DoCommand(ac, av)); 288155192Srwatson} 289155192Srwatson 290155192Srwatson/* 291155192Srwatson * Execute the command 292155192Srwatson */ 293155192Srwatsonstatic int 294155192SrwatsonDoCommand(int ac, char **av) 295155192Srwatson{ 296155192Srwatson const struct ngcmd *cmd; 297155192Srwatson int rtn; 298155192Srwatson 299155192Srwatson if (ac == 0 || *av[0] == 0) 300155192Srwatson return(CMDRTN_OK); 301155192Srwatson if ((cmd = FindCommand(av[0])) == NULL) 302155192Srwatson return(CMDRTN_ERROR); 303155192Srwatson if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE) 304155192Srwatson warnx("usage: %s", cmd->cmd); 305155192Srwatson return(rtn); 306155192Srwatson} 307155192Srwatson 308155406Srwatson/* 309155406Srwatson * Find a command 310155406Srwatson */ 311155406Srwatsonstatic const struct ngcmd * 312155406SrwatsonFindCommand(const char *string) 313155192Srwatson{ 314155192Srwatson int k, found = -1; 315155192Srwatson 316155406Srwatson for (k = 0; cmds[k] != NULL; k++) { 317155192Srwatson if (MatchCommand(cmds[k], string)) { 318155192Srwatson if (found != -1) { 319155406Srwatson warnx("\"%s\": ambiguous command", string); 320155406Srwatson return(NULL); 321155192Srwatson } 322155192Srwatson found = k; 323155192Srwatson } 324155192Srwatson } 325155192Srwatson if (found == -1) { 326155192Srwatson warnx("\"%s\": unknown command", string); 327155192Srwatson return(NULL); 328155192Srwatson } 329156888Srwatson return(cmds[found]); 330156888Srwatson} 331156888Srwatson 332156888Srwatson/* 333156888Srwatson * See if string matches a prefix of "cmd" (or an alias) case insensitively 334156888Srwatson */ 335156888Srwatsonstatic int 336155192SrwatsonMatchCommand(const struct ngcmd *cmd, const char *s) 337155192Srwatson{ 338155192Srwatson int a; 339155192Srwatson 340155192Srwatson /* Try to match command, ignoring the usage stuff */ 341155192Srwatson if (strlen(s) <= strcspn(cmd->cmd, WHITESPACE)) { 342159269Srwatson if (strncasecmp(s, cmd->cmd, strlen(s)) == 0) 343159269Srwatson return (1); 344159269Srwatson } 345155192Srwatson 346155192Srwatson /* Try to match aliases */ 347155192Srwatson for (a = 0; a < MAX_CMD_ALIAS && cmd->aliases[a] != NULL; a++) { 348155192Srwatson if (strlen(cmd->aliases[a]) >= strlen(s)) { 349155192Srwatson if (strncasecmp(s, cmd->aliases[a], strlen(s)) == 0) 350155192Srwatson return (1); 351155192Srwatson } 352155192Srwatson } 353155192Srwatson 354155192Srwatson /* No match */ 355155192Srwatson return (0); 356155192Srwatson} 357155192Srwatson 358155192Srwatson/* 359155192Srwatson * ReadCmd() 360155192Srwatson */ 361155192Srwatsonstatic int 362156889SrwatsonReadCmd(int ac, char **av) 363155192Srwatson{ 364155192Srwatson FILE *fp; 365155192Srwatson int rtn; 366155192Srwatson 367155192Srwatson /* Open file */ 368155192Srwatson switch (ac) { 369155192Srwatson case 2: 370155192Srwatson if ((fp = fopen(av[1], "r")) == NULL) { 371155192Srwatson warn("%s", av[1]); 372156889Srwatson return(CMDRTN_ERROR); 373155192Srwatson } 374155192Srwatson break; 375155192Srwatson default: 376155192Srwatson return(CMDRTN_USAGE); 377155192Srwatson } 378155192Srwatson 379155192Srwatson /* Process it */ 380155192Srwatson rtn = ReadFile(fp); 381155192Srwatson fclose(fp); 382155192Srwatson return(rtn); 383155192Srwatson} 384155192Srwatson 385155192Srwatson/* 386155192Srwatson * HelpCmd() 387155192Srwatson */ 388155192Srwatsonstatic int 389155192SrwatsonHelpCmd(int ac, char **av) 390159269Srwatson{ 391159269Srwatson const struct ngcmd *cmd; 392159269Srwatson int k; 393155192Srwatson 394159269Srwatson switch (ac) { 395159269Srwatson case 0: 396159269Srwatson case 1: 397159269Srwatson /* Show all commands */ 398159269Srwatson printf("Available commands:\n"); 399159269Srwatson for (k = 0; cmds[k] != NULL; k++) { 400162380Scsjp char *s, buf[100]; 401162380Scsjp 402155192Srwatson cmd = cmds[k]; 403155192Srwatson snprintf(buf, sizeof(buf), "%s", cmd->cmd); 404155192Srwatson for (s = buf; *s != '\0' && !isspace(*s); s++); 405159275Srwatson *s = '\0'; 406155192Srwatson printf(" %-10s %s\n", buf, cmd->desc); 407155192Srwatson } 408155192Srwatson return(CMDRTN_OK); 409155192Srwatson default: 410155192Srwatson /* Show help on a specific command */ 411155192Srwatson if ((cmd = FindCommand(av[1])) != NULL) { 412155192Srwatson printf("usage: %s\n", cmd->cmd); 413155192Srwatson if (cmd->aliases[0] != NULL) { 414155192Srwatson int a = 0; 415155192Srwatson 416155192Srwatson printf("Aliases: "); 417155192Srwatson while (1) { 418155192Srwatson printf("%s", cmd->aliases[a++]); 419155192Srwatson if (a == MAX_CMD_ALIAS 420155192Srwatson || cmd->aliases[a] == NULL) { 421155192Srwatson printf("\n"); 422155192Srwatson break; 423155192Srwatson } 424155192Srwatson printf(", "); 425155192Srwatson } 426155192Srwatson } 427155192Srwatson printf("Summary: %s\n", cmd->desc); 428155192Srwatson if (cmd->help != NULL) { 429155192Srwatson const char *s; 430155192Srwatson char buf[65]; 431159275Srwatson int tot, len, done; 432155192Srwatson 433155192Srwatson printf("Description:\n"); 434156889Srwatson for (s = cmd->help; *s != '\0'; s += len) { 435155192Srwatson while (isspace(*s)) 436155192Srwatson s++; 437155192Srwatson tot = snprintf(buf, 438155192Srwatson sizeof(buf), "%s", s); 439155192Srwatson len = strlen(buf); 440155192Srwatson done = len == tot; 441155192Srwatson if (!done) { 442159261Srwatson while (len > 0 443155192Srwatson && !isspace(buf[len-1])) 444155192Srwatson buf[--len] = '\0'; 445155192Srwatson } 446155192Srwatson printf(" %s\n", buf); 447155192Srwatson } 448155192Srwatson } 449155192Srwatson } 450159261Srwatson } 451155192Srwatson return(CMDRTN_OK); 452155192Srwatson} 453155192Srwatson 454155192Srwatson/* 455155192Srwatson * QuitCmd() 456155192Srwatson */ 457155192Srwatsonstatic int 458155192SrwatsonQuitCmd(int ac __unused, char **av __unused) 459155192Srwatson{ 460155192Srwatson return(CMDRTN_QUIT); 461155192Srwatson} 462155192Srwatson 463155192Srwatson/* 464159269Srwatson * Dump data in hex and ASCII form 465159269Srwatson */ 466159269Srwatsonvoid 467155192SrwatsonDumpAscii(const u_char *buf, int len) 468155192Srwatson{ 469155192Srwatson char ch, sbuf[100]; 470155192Srwatson int k, count; 471155192Srwatson 472155192Srwatson for (count = 0; count < len; count += DUMP_BYTES_PER_LINE) { 473155192Srwatson snprintf(sbuf, sizeof(sbuf), "%04x: ", count); 474155192Srwatson for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 475162950Srwatson if (count + k < len) { 476162950Srwatson snprintf(sbuf + strlen(sbuf), 477155192Srwatson sizeof(sbuf) - strlen(sbuf), 478155192Srwatson "%02x ", buf[count + k]); 479155192Srwatson } else { 480155192Srwatson snprintf(sbuf + strlen(sbuf), 481159269Srwatson sizeof(sbuf) - strlen(sbuf), " "); 482159269Srwatson } 483155192Srwatson } 484155192Srwatson snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " "); 485155192Srwatson for (k = 0; k < DUMP_BYTES_PER_LINE; k++) { 486155192Srwatson if (count + k < len) { 487155192Srwatson ch = isprint(buf[count + k]) ? 488155192Srwatson buf[count + k] : '.'; 489159269Srwatson snprintf(sbuf + strlen(sbuf), 490159269Srwatson sizeof(sbuf) - strlen(sbuf), "%c", ch); 491155192Srwatson } else { 492155192Srwatson snprintf(sbuf + strlen(sbuf), 493155192Srwatson sizeof(sbuf) - strlen(sbuf), " "); 494156889Srwatson } 495155192Srwatson } 496156889Srwatson printf("%s\n", sbuf); 497155192Srwatson } 498155192Srwatson} 499159269Srwatson 500159269Srwatson/* 501155192Srwatson * Usage() 502155192Srwatson */ 503155192Srwatsonstatic void 504155192SrwatsonUsage(const char *msg) 505155192Srwatson{ 506155192Srwatson if (msg) 507155192Srwatson warnx("%s", msg); 508155192Srwatson fprintf(stderr, 509155192Srwatson "usage: ngctl [-d] [-f file] [-n name] [command ...]\n"); 510155192Srwatson exit(EX_USAGE); 511155192Srwatson} 512155192Srwatson