14cf49a43SJulian Elischer 24cf49a43SJulian Elischer /* 34cf49a43SJulian Elischer * main.c 44cf49a43SJulian Elischer * 54cf49a43SJulian Elischer * Copyright (c) 1996-1999 Whistle Communications, Inc. 64cf49a43SJulian Elischer * All rights reserved. 74cf49a43SJulian Elischer * 84cf49a43SJulian Elischer * Subject to the following obligations and disclaimer of warranty, use and 94cf49a43SJulian Elischer * redistribution of this software, in source or object code forms, with or 104cf49a43SJulian Elischer * without modifications are expressly permitted by Whistle Communications; 114cf49a43SJulian Elischer * provided, however, that: 124cf49a43SJulian Elischer * 1. Any and all reproductions of the source or object code must include the 134cf49a43SJulian Elischer * copyright notice above and the following disclaimer of warranties; and 144cf49a43SJulian Elischer * 2. No rights are granted, in any manner or form, to use Whistle 154cf49a43SJulian Elischer * Communications, Inc. trademarks, including the mark "WHISTLE 164cf49a43SJulian Elischer * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 174cf49a43SJulian Elischer * such appears in the above copyright notice or in the software. 184cf49a43SJulian Elischer * 194cf49a43SJulian Elischer * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 204cf49a43SJulian Elischer * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 214cf49a43SJulian Elischer * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 224cf49a43SJulian Elischer * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 234cf49a43SJulian Elischer * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 244cf49a43SJulian Elischer * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 254cf49a43SJulian Elischer * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 264cf49a43SJulian Elischer * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 274cf49a43SJulian Elischer * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 284cf49a43SJulian Elischer * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 294cf49a43SJulian Elischer * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 304cf49a43SJulian Elischer * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 314cf49a43SJulian Elischer * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 324cf49a43SJulian Elischer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 334cf49a43SJulian Elischer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 344cf49a43SJulian Elischer * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 354cf49a43SJulian Elischer * OF SUCH DAMAGE. 364cf49a43SJulian Elischer * 374cf49a43SJulian Elischer * $FreeBSD$ 384cf49a43SJulian Elischer */ 394cf49a43SJulian Elischer 404cf49a43SJulian Elischer #include "ngctl.h" 414cf49a43SJulian Elischer 424cf49a43SJulian Elischer #define PROMPT "+ " 434cf49a43SJulian Elischer #define MAX_ARGS 512 444cf49a43SJulian Elischer #define WHITESPACE " \t\r\n\v\f" 454cf49a43SJulian Elischer 464cf49a43SJulian Elischer /* Internal functions */ 474cf49a43SJulian Elischer static int ReadFile(FILE *fp); 484cf49a43SJulian Elischer static int DoParseCommand(char *line); 494cf49a43SJulian Elischer static int DoCommand(int ac, char **av); 504cf49a43SJulian Elischer static int DoInteractive(void); 514cf49a43SJulian Elischer static const struct ngcmd *FindCommand(const char *string); 524cf49a43SJulian Elischer static void Usage(const char *msg); 534cf49a43SJulian Elischer static int ReadCmd(int ac, char **av); 544cf49a43SJulian Elischer static int HelpCmd(int ac, char **av); 554cf49a43SJulian Elischer static int QuitCmd(int ac, char **av); 564cf49a43SJulian Elischer 574cf49a43SJulian Elischer /* List of commands */ 584cf49a43SJulian Elischer static const struct ngcmd *const cmds[] = { 594cf49a43SJulian Elischer &connect_cmd, 604cf49a43SJulian Elischer &debug_cmd, 614cf49a43SJulian Elischer &help_cmd, 624cf49a43SJulian Elischer &list_cmd, 634cf49a43SJulian Elischer &mkpeer_cmd, 644cf49a43SJulian Elischer &name_cmd, 654cf49a43SJulian Elischer &read_cmd, 664cf49a43SJulian Elischer &rmhook_cmd, 674cf49a43SJulian Elischer &show_cmd, 684cf49a43SJulian Elischer &shutdown_cmd, 694cf49a43SJulian Elischer &status_cmd, 704cf49a43SJulian Elischer &types_cmd, 714cf49a43SJulian Elischer &quit_cmd, 724cf49a43SJulian Elischer NULL 734cf49a43SJulian Elischer }; 744cf49a43SJulian Elischer 754cf49a43SJulian Elischer /* Commands defined in this file */ 764cf49a43SJulian Elischer const struct ngcmd read_cmd = { 774cf49a43SJulian Elischer ReadCmd, 784cf49a43SJulian Elischer "read <filename>", 794cf49a43SJulian Elischer "Read and execute commands from a file", 804cf49a43SJulian Elischer NULL 814cf49a43SJulian Elischer }; 824cf49a43SJulian Elischer const struct ngcmd help_cmd = { 834cf49a43SJulian Elischer HelpCmd, 844cf49a43SJulian Elischer "help [command]", 854cf49a43SJulian Elischer "Show command summary or get more help on a specific command", 864cf49a43SJulian Elischer NULL 874cf49a43SJulian Elischer }; 884cf49a43SJulian Elischer const struct ngcmd quit_cmd = { 894cf49a43SJulian Elischer QuitCmd, 904cf49a43SJulian Elischer "quit", 914cf49a43SJulian Elischer "Exit program", 924cf49a43SJulian Elischer NULL 934cf49a43SJulian Elischer }; 944cf49a43SJulian Elischer 954cf49a43SJulian Elischer /* Our control and data sockets */ 964cf49a43SJulian Elischer int csock, dsock; 974cf49a43SJulian Elischer 984cf49a43SJulian Elischer /* 994cf49a43SJulian Elischer * main() 1004cf49a43SJulian Elischer */ 1014cf49a43SJulian Elischer int 1024cf49a43SJulian Elischer main(int ac, char *av[]) 1034cf49a43SJulian Elischer { 1044cf49a43SJulian Elischer char name[NG_NODELEN + 1]; 1054cf49a43SJulian Elischer int interactive = isatty(0) && isatty(1); 1064cf49a43SJulian Elischer FILE *fp = NULL; 1074cf49a43SJulian Elischer int ch, rtn = 0; 1084cf49a43SJulian Elischer 1094cf49a43SJulian Elischer /* Set default node name */ 1104cf49a43SJulian Elischer snprintf(name, sizeof(name), "ngctl%d", getpid()); 1114cf49a43SJulian Elischer 1124cf49a43SJulian Elischer /* Parse command line */ 1134cf49a43SJulian Elischer while ((ch = getopt(ac, av, "df:n:")) != EOF) { 1144cf49a43SJulian Elischer switch (ch) { 1154cf49a43SJulian Elischer case 'd': 1164cf49a43SJulian Elischer NgSetDebug(NgSetDebug(-1) + 1); 1174cf49a43SJulian Elischer break; 1184cf49a43SJulian Elischer case 'f': 1194cf49a43SJulian Elischer if (strcmp(optarg, "-") == 0) 1204cf49a43SJulian Elischer fp = stdin; 1214cf49a43SJulian Elischer else if ((fp = fopen(optarg, "r")) == NULL) 1224cf49a43SJulian Elischer err(EX_NOINPUT, "%s", optarg); 1234cf49a43SJulian Elischer break; 1244cf49a43SJulian Elischer case 'n': 1254cf49a43SJulian Elischer snprintf(name, sizeof(name), "%s", optarg); 1264cf49a43SJulian Elischer break; 1274cf49a43SJulian Elischer case '?': 1284cf49a43SJulian Elischer default: 1294cf49a43SJulian Elischer Usage((char *)NULL); 1304cf49a43SJulian Elischer break; 1314cf49a43SJulian Elischer } 1324cf49a43SJulian Elischer } 1334cf49a43SJulian Elischer ac -= optind; 1344cf49a43SJulian Elischer av += optind; 1354cf49a43SJulian Elischer 1364cf49a43SJulian Elischer /* Create a new socket node */ 1374cf49a43SJulian Elischer if (NgMkSockNode(name, &csock, &dsock) < 0) 1384cf49a43SJulian Elischer err(EX_OSERR, "can't create node"); 1394cf49a43SJulian Elischer 1404cf49a43SJulian Elischer /* Do commands as requested */ 1414cf49a43SJulian Elischer if (ac == 0) { 1424cf49a43SJulian Elischer if (fp != NULL) { 1434cf49a43SJulian Elischer rtn = ReadFile(fp); 1444cf49a43SJulian Elischer } else if (interactive) { 1454cf49a43SJulian Elischer rtn = DoInteractive(); 1464cf49a43SJulian Elischer } else 1474cf49a43SJulian Elischer Usage("no command specified"); 1484cf49a43SJulian Elischer } else { 1494cf49a43SJulian Elischer rtn = DoCommand(ac, av); 1504cf49a43SJulian Elischer } 1514cf49a43SJulian Elischer 1524cf49a43SJulian Elischer /* Convert command return code into system exit code */ 1534cf49a43SJulian Elischer switch (rtn) { 1544cf49a43SJulian Elischer case CMDRTN_OK: 1554cf49a43SJulian Elischer case CMDRTN_QUIT: 1564cf49a43SJulian Elischer rtn = 0; 1574cf49a43SJulian Elischer break; 1584cf49a43SJulian Elischer case CMDRTN_USAGE: 1594cf49a43SJulian Elischer rtn = EX_USAGE; 1604cf49a43SJulian Elischer break; 1614cf49a43SJulian Elischer case CMDRTN_ERROR: 1624cf49a43SJulian Elischer rtn = EX_OSERR; 1634cf49a43SJulian Elischer break; 1644cf49a43SJulian Elischer } 1654cf49a43SJulian Elischer return(rtn); 1664cf49a43SJulian Elischer } 1674cf49a43SJulian Elischer 1684cf49a43SJulian Elischer /* 1694cf49a43SJulian Elischer * Process commands from a file 1704cf49a43SJulian Elischer */ 1714cf49a43SJulian Elischer static int 1724cf49a43SJulian Elischer ReadFile(FILE *fp) 1734cf49a43SJulian Elischer { 1744cf49a43SJulian Elischer char line[LINE_MAX]; 1754cf49a43SJulian Elischer int num, rtn; 1764cf49a43SJulian Elischer 1774cf49a43SJulian Elischer for (num = 1; fgets(line, sizeof(line), fp) != NULL; num++) { 1784cf49a43SJulian Elischer if (*line == '#') 1794cf49a43SJulian Elischer continue; 1804cf49a43SJulian Elischer if ((rtn = DoParseCommand(line)) != 0) { 1814cf49a43SJulian Elischer warnx("line %d: error in file", num); 1824cf49a43SJulian Elischer return(rtn); 1834cf49a43SJulian Elischer } 1844cf49a43SJulian Elischer } 1854cf49a43SJulian Elischer return(CMDRTN_OK); 1864cf49a43SJulian Elischer } 1874cf49a43SJulian Elischer 1884cf49a43SJulian Elischer /* 1894cf49a43SJulian Elischer * Interactive mode 1904cf49a43SJulian Elischer */ 1914cf49a43SJulian Elischer static int 1924cf49a43SJulian Elischer DoInteractive(void) 1934cf49a43SJulian Elischer { 1944cf49a43SJulian Elischer char buf[LINE_MAX]; 1954cf49a43SJulian Elischer 1964cf49a43SJulian Elischer /* Read commands from stdin */ 1974cf49a43SJulian Elischer (*help_cmd.func)(0, NULL); 1984cf49a43SJulian Elischer do { 1994cf49a43SJulian Elischer printf("%s", PROMPT); 2004cf49a43SJulian Elischer if (fgets(buf, sizeof(buf), stdin) == NULL) 2014cf49a43SJulian Elischer break; 2024cf49a43SJulian Elischer fflush(stdout); 2034cf49a43SJulian Elischer } while (DoParseCommand(buf) != CMDRTN_QUIT); 2044cf49a43SJulian Elischer return(CMDRTN_QUIT); 2054cf49a43SJulian Elischer } 2064cf49a43SJulian Elischer 2074cf49a43SJulian Elischer /* 2084cf49a43SJulian Elischer * Parse a command line and execute the command 2094cf49a43SJulian Elischer */ 2104cf49a43SJulian Elischer static int 2114cf49a43SJulian Elischer DoParseCommand(char *line) 2124cf49a43SJulian Elischer { 2134cf49a43SJulian Elischer char *av[MAX_ARGS]; 2144cf49a43SJulian Elischer int ac; 2154cf49a43SJulian Elischer 2164cf49a43SJulian Elischer /* Parse line */ 2174cf49a43SJulian Elischer for (ac = 0, av[0] = strtok(line, WHITESPACE); 2184cf49a43SJulian Elischer ac < MAX_ARGS - 1 && av[ac]; 2194cf49a43SJulian Elischer av[++ac] = strtok(NULL, WHITESPACE)); 2204cf49a43SJulian Elischer 2214cf49a43SJulian Elischer /* Do command */ 2224cf49a43SJulian Elischer return(DoCommand(ac, av)); 2234cf49a43SJulian Elischer } 2244cf49a43SJulian Elischer 2254cf49a43SJulian Elischer /* 2264cf49a43SJulian Elischer * Execute the command 2274cf49a43SJulian Elischer */ 2284cf49a43SJulian Elischer static int 2294cf49a43SJulian Elischer DoCommand(int ac, char **av) 2304cf49a43SJulian Elischer { 2314cf49a43SJulian Elischer const struct ngcmd *cmd; 2324cf49a43SJulian Elischer int rtn; 2334cf49a43SJulian Elischer 2344cf49a43SJulian Elischer if (ac == 0 || *av[0] == 0) 2354cf49a43SJulian Elischer return(CMDRTN_OK); 2364cf49a43SJulian Elischer if ((cmd = FindCommand(av[0])) == NULL) 2374cf49a43SJulian Elischer return(CMDRTN_ERROR); 2384cf49a43SJulian Elischer if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE) 2394cf49a43SJulian Elischer warnx("usage: %s", cmd->cmd); 2404cf49a43SJulian Elischer return(rtn); 2414cf49a43SJulian Elischer } 2424cf49a43SJulian Elischer 2434cf49a43SJulian Elischer /* 2444cf49a43SJulian Elischer * Find a command 2454cf49a43SJulian Elischer */ 2464cf49a43SJulian Elischer static const struct ngcmd * 2474cf49a43SJulian Elischer FindCommand(const char *string) 2484cf49a43SJulian Elischer { 2494cf49a43SJulian Elischer const struct ngcmd *cmd; 2504cf49a43SJulian Elischer int k, len, found; 2514cf49a43SJulian Elischer 2524cf49a43SJulian Elischer if (strcmp(string, "?") == 0) 2534cf49a43SJulian Elischer string = "help"; 2544cf49a43SJulian Elischer for (k = 0, found = -1; cmds[k]; k++) { 2554cf49a43SJulian Elischer cmd = cmds[k]; 2564cf49a43SJulian Elischer len = strcspn(cmd->cmd, WHITESPACE); 2574cf49a43SJulian Elischer if (len > strlen(string)) 2584cf49a43SJulian Elischer len = strlen(string); 2594cf49a43SJulian Elischer if (!strncasecmp(string, cmd->cmd, len)) { 2604cf49a43SJulian Elischer if (found != -1) { 2614cf49a43SJulian Elischer warnx("\"%s\": ambiguous command", string); 2624cf49a43SJulian Elischer return(NULL); 2634cf49a43SJulian Elischer } 2644cf49a43SJulian Elischer found = k; 2654cf49a43SJulian Elischer } 2664cf49a43SJulian Elischer } 2674cf49a43SJulian Elischer if (found == -1) { 2684cf49a43SJulian Elischer warnx("\"%s\": unknown command", string); 2694cf49a43SJulian Elischer return(NULL); 2704cf49a43SJulian Elischer } 2714cf49a43SJulian Elischer return(cmds[found]); 2724cf49a43SJulian Elischer } 2734cf49a43SJulian Elischer 2744cf49a43SJulian Elischer /* 2754cf49a43SJulian Elischer * ReadCmd() 2764cf49a43SJulian Elischer */ 2774cf49a43SJulian Elischer static int 2784cf49a43SJulian Elischer ReadCmd(int ac, char **av) 2794cf49a43SJulian Elischer { 2804cf49a43SJulian Elischer FILE *fp; 2814cf49a43SJulian Elischer int rtn; 2824cf49a43SJulian Elischer 2834cf49a43SJulian Elischer /* Open file */ 2844cf49a43SJulian Elischer switch (ac) { 2854cf49a43SJulian Elischer case 2: 2864cf49a43SJulian Elischer if ((fp = fopen(av[1], "r")) == NULL) 2874cf49a43SJulian Elischer warn("%s", av[1]); 2884cf49a43SJulian Elischer return(CMDRTN_ERROR); 2894cf49a43SJulian Elischer default: 2904cf49a43SJulian Elischer return(CMDRTN_USAGE); 2914cf49a43SJulian Elischer } 2924cf49a43SJulian Elischer 2934cf49a43SJulian Elischer /* Process it */ 2944cf49a43SJulian Elischer rtn = ReadFile(fp); 2954cf49a43SJulian Elischer fclose(fp); 2964cf49a43SJulian Elischer return(rtn); 2974cf49a43SJulian Elischer } 2984cf49a43SJulian Elischer 2994cf49a43SJulian Elischer /* 3004cf49a43SJulian Elischer * HelpCmd() 3014cf49a43SJulian Elischer */ 3024cf49a43SJulian Elischer static int 3034cf49a43SJulian Elischer HelpCmd(int ac, char **av) 3044cf49a43SJulian Elischer { 3054cf49a43SJulian Elischer const struct ngcmd *cmd; 3064cf49a43SJulian Elischer int k; 3074cf49a43SJulian Elischer 3084cf49a43SJulian Elischer switch (ac) { 3094cf49a43SJulian Elischer case 0: 3104cf49a43SJulian Elischer case 1: 3114cf49a43SJulian Elischer /* Show all commands */ 3124cf49a43SJulian Elischer printf("Available commands:\n"); 3134cf49a43SJulian Elischer for (k = 0; cmds[k] != NULL; k++) { 3144cf49a43SJulian Elischer char *s, buf[100]; 3154cf49a43SJulian Elischer 3164cf49a43SJulian Elischer cmd = cmds[k]; 3174cf49a43SJulian Elischer snprintf(buf, sizeof(buf), "%s", cmd->cmd); 3184cf49a43SJulian Elischer for (s = buf; *s != '\0' && !isspace(*s); s++); 3194cf49a43SJulian Elischer *s = '\0'; 3204cf49a43SJulian Elischer printf(" %-10s %s\n", buf, cmd->desc); 3214cf49a43SJulian Elischer } 3224cf49a43SJulian Elischer return(CMDRTN_OK); 3234cf49a43SJulian Elischer default: 3244cf49a43SJulian Elischer /* Show help on a specific command */ 3254cf49a43SJulian Elischer if ((cmd = FindCommand(av[1])) != NULL) { 3264cf49a43SJulian Elischer printf("Usage: %s\n", cmd->cmd); 3274cf49a43SJulian Elischer printf("Summary: %s\n", cmd->desc); 3284cf49a43SJulian Elischer if (cmd->help != NULL) { 3294cf49a43SJulian Elischer const char *s; 3304cf49a43SJulian Elischer char buf[65]; 3314cf49a43SJulian Elischer int tot, len, done; 3324cf49a43SJulian Elischer 3334cf49a43SJulian Elischer printf("Description:\n"); 3344cf49a43SJulian Elischer for (s = cmd->help; *s != '\0'; s += len) { 3354cf49a43SJulian Elischer while (isspace(*s)) 3364cf49a43SJulian Elischer s++; 3374cf49a43SJulian Elischer tot = snprintf(buf, 3384cf49a43SJulian Elischer sizeof(buf), "%s", s); 3394cf49a43SJulian Elischer len = strlen(buf); 3404cf49a43SJulian Elischer done = len == tot; 3414cf49a43SJulian Elischer if (!done) { 3424cf49a43SJulian Elischer while (len > 0 3434cf49a43SJulian Elischer && !isspace(buf[len-1])) 3444cf49a43SJulian Elischer buf[--len] = '\0'; 3454cf49a43SJulian Elischer } 3464cf49a43SJulian Elischer printf(" %s\n", buf); 3474cf49a43SJulian Elischer } 3484cf49a43SJulian Elischer } 3494cf49a43SJulian Elischer } 3504cf49a43SJulian Elischer } 3514cf49a43SJulian Elischer return(CMDRTN_OK); 3524cf49a43SJulian Elischer } 3534cf49a43SJulian Elischer 3544cf49a43SJulian Elischer /* 3554cf49a43SJulian Elischer * QuitCmd() 3564cf49a43SJulian Elischer */ 3574cf49a43SJulian Elischer static int 3584cf49a43SJulian Elischer QuitCmd(int ac, char **av) 3594cf49a43SJulian Elischer { 3604cf49a43SJulian Elischer return(CMDRTN_QUIT); 3614cf49a43SJulian Elischer } 3624cf49a43SJulian Elischer 3634cf49a43SJulian Elischer /* 3644cf49a43SJulian Elischer * Usage() 3654cf49a43SJulian Elischer */ 3664cf49a43SJulian Elischer static void 3674cf49a43SJulian Elischer Usage(const char *msg) 3684cf49a43SJulian Elischer { 3694cf49a43SJulian Elischer if (msg) 3704cf49a43SJulian Elischer warnx("%s", msg); 3714cf49a43SJulian Elischer errx(EX_USAGE, "usage: ngctl [-d] [-f file] [-n name] [command ...]"); 3724cf49a43SJulian Elischer } 3734cf49a43SJulian Elischer 374