main.c revision 52419
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 52419 1999-10-21 09:06:11Z julian $ 3852419Sjulian */ 3952419Sjulian 4052419Sjulian#include "ngctl.h" 4152419Sjulian 4252419Sjulian#define PROMPT "+ " 4352419Sjulian#define MAX_ARGS 512 4452419Sjulian#define WHITESPACE " \t\r\n\v\f" 4552419Sjulian 4652419Sjulian/* Internal functions */ 4752419Sjulianstatic int ReadFile(FILE *fp); 4852419Sjulianstatic int DoParseCommand(char *line); 4952419Sjulianstatic int DoCommand(int ac, char **av); 5052419Sjulianstatic int DoInteractive(void); 5152419Sjulianstatic const struct ngcmd *FindCommand(const char *string); 5252419Sjulianstatic void Usage(const char *msg); 5352419Sjulianstatic int ReadCmd(int ac, char **av); 5452419Sjulianstatic int HelpCmd(int ac, char **av); 5552419Sjulianstatic int QuitCmd(int ac, char **av); 5652419Sjulian 5752419Sjulian/* List of commands */ 5852419Sjulianstatic const struct ngcmd *const cmds[] = { 5952419Sjulian &connect_cmd, 6052419Sjulian &debug_cmd, 6152419Sjulian &help_cmd, 6252419Sjulian &list_cmd, 6352419Sjulian &mkpeer_cmd, 6452419Sjulian &name_cmd, 6552419Sjulian &read_cmd, 6652419Sjulian &rmhook_cmd, 6752419Sjulian &show_cmd, 6852419Sjulian &shutdown_cmd, 6952419Sjulian &status_cmd, 7052419Sjulian &types_cmd, 7152419Sjulian &quit_cmd, 7252419Sjulian NULL 7352419Sjulian}; 7452419Sjulian 7552419Sjulian/* Commands defined in this file */ 7652419Sjulianconst struct ngcmd read_cmd = { 7752419Sjulian ReadCmd, 7852419Sjulian "read <filename>", 7952419Sjulian "Read and execute commands from a file", 8052419Sjulian NULL 8152419Sjulian}; 8252419Sjulianconst struct ngcmd help_cmd = { 8352419Sjulian HelpCmd, 8452419Sjulian "help [command]", 8552419Sjulian "Show command summary or get more help on a specific command", 8652419Sjulian NULL 8752419Sjulian}; 8852419Sjulianconst struct ngcmd quit_cmd = { 8952419Sjulian QuitCmd, 9052419Sjulian "quit", 9152419Sjulian "Exit program", 9252419Sjulian NULL 9352419Sjulian}; 9452419Sjulian 9552419Sjulian/* Our control and data sockets */ 9652419Sjulianint csock, dsock; 9752419Sjulian 9852419Sjulian/* 9952419Sjulian * main() 10052419Sjulian */ 10152419Sjulianint 10252419Sjulianmain(int ac, char *av[]) 10352419Sjulian{ 10452419Sjulian char name[NG_NODELEN + 1]; 10552419Sjulian int interactive = isatty(0) && isatty(1); 10652419Sjulian FILE *fp = NULL; 10752419Sjulian int ch, rtn = 0; 10852419Sjulian 10952419Sjulian /* Set default node name */ 11052419Sjulian snprintf(name, sizeof(name), "ngctl%d", getpid()); 11152419Sjulian 11252419Sjulian /* Parse command line */ 11352419Sjulian while ((ch = getopt(ac, av, "df:n:")) != EOF) { 11452419Sjulian switch (ch) { 11552419Sjulian case 'd': 11652419Sjulian NgSetDebug(NgSetDebug(-1) + 1); 11752419Sjulian break; 11852419Sjulian case 'f': 11952419Sjulian if (strcmp(optarg, "-") == 0) 12052419Sjulian fp = stdin; 12152419Sjulian else if ((fp = fopen(optarg, "r")) == NULL) 12252419Sjulian err(EX_NOINPUT, "%s", optarg); 12352419Sjulian break; 12452419Sjulian case 'n': 12552419Sjulian snprintf(name, sizeof(name), "%s", optarg); 12652419Sjulian break; 12752419Sjulian case '?': 12852419Sjulian default: 12952419Sjulian Usage((char *)NULL); 13052419Sjulian break; 13152419Sjulian } 13252419Sjulian } 13352419Sjulian ac -= optind; 13452419Sjulian av += optind; 13552419Sjulian 13652419Sjulian /* Create a new socket node */ 13752419Sjulian if (NgMkSockNode(name, &csock, &dsock) < 0) 13852419Sjulian err(EX_OSERR, "can't create node"); 13952419Sjulian 14052419Sjulian /* Do commands as requested */ 14152419Sjulian if (ac == 0) { 14252419Sjulian if (fp != NULL) { 14352419Sjulian rtn = ReadFile(fp); 14452419Sjulian } else if (interactive) { 14552419Sjulian rtn = DoInteractive(); 14652419Sjulian } else 14752419Sjulian Usage("no command specified"); 14852419Sjulian } else { 14952419Sjulian rtn = DoCommand(ac, av); 15052419Sjulian } 15152419Sjulian 15252419Sjulian /* Convert command return code into system exit code */ 15352419Sjulian switch (rtn) { 15452419Sjulian case CMDRTN_OK: 15552419Sjulian case CMDRTN_QUIT: 15652419Sjulian rtn = 0; 15752419Sjulian break; 15852419Sjulian case CMDRTN_USAGE: 15952419Sjulian rtn = EX_USAGE; 16052419Sjulian break; 16152419Sjulian case CMDRTN_ERROR: 16252419Sjulian rtn = EX_OSERR; 16352419Sjulian break; 16452419Sjulian } 16552419Sjulian return(rtn); 16652419Sjulian} 16752419Sjulian 16852419Sjulian/* 16952419Sjulian * Process commands from a file 17052419Sjulian */ 17152419Sjulianstatic int 17252419SjulianReadFile(FILE *fp) 17352419Sjulian{ 17452419Sjulian char line[LINE_MAX]; 17552419Sjulian int num, rtn; 17652419Sjulian 17752419Sjulian for (num = 1; fgets(line, sizeof(line), fp) != NULL; num++) { 17852419Sjulian if (*line == '#') 17952419Sjulian continue; 18052419Sjulian if ((rtn = DoParseCommand(line)) != 0) { 18152419Sjulian warnx("line %d: error in file", num); 18252419Sjulian return(rtn); 18352419Sjulian } 18452419Sjulian } 18552419Sjulian return(CMDRTN_OK); 18652419Sjulian} 18752419Sjulian 18852419Sjulian/* 18952419Sjulian * Interactive mode 19052419Sjulian */ 19152419Sjulianstatic int 19252419SjulianDoInteractive(void) 19352419Sjulian{ 19452419Sjulian char buf[LINE_MAX]; 19552419Sjulian 19652419Sjulian /* Read commands from stdin */ 19752419Sjulian (*help_cmd.func)(0, NULL); 19852419Sjulian do { 19952419Sjulian printf("%s", PROMPT); 20052419Sjulian if (fgets(buf, sizeof(buf), stdin) == NULL) 20152419Sjulian break; 20252419Sjulian fflush(stdout); 20352419Sjulian } while (DoParseCommand(buf) != CMDRTN_QUIT); 20452419Sjulian return(CMDRTN_QUIT); 20552419Sjulian} 20652419Sjulian 20752419Sjulian/* 20852419Sjulian * Parse a command line and execute the command 20952419Sjulian */ 21052419Sjulianstatic int 21152419SjulianDoParseCommand(char *line) 21252419Sjulian{ 21352419Sjulian char *av[MAX_ARGS]; 21452419Sjulian int ac; 21552419Sjulian 21652419Sjulian /* Parse line */ 21752419Sjulian for (ac = 0, av[0] = strtok(line, WHITESPACE); 21852419Sjulian ac < MAX_ARGS - 1 && av[ac]; 21952419Sjulian av[++ac] = strtok(NULL, WHITESPACE)); 22052419Sjulian 22152419Sjulian /* Do command */ 22252419Sjulian return(DoCommand(ac, av)); 22352419Sjulian} 22452419Sjulian 22552419Sjulian/* 22652419Sjulian * Execute the command 22752419Sjulian */ 22852419Sjulianstatic int 22952419SjulianDoCommand(int ac, char **av) 23052419Sjulian{ 23152419Sjulian const struct ngcmd *cmd; 23252419Sjulian int rtn; 23352419Sjulian 23452419Sjulian if (ac == 0 || *av[0] == 0) 23552419Sjulian return(CMDRTN_OK); 23652419Sjulian if ((cmd = FindCommand(av[0])) == NULL) 23752419Sjulian return(CMDRTN_ERROR); 23852419Sjulian if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE) 23952419Sjulian warnx("usage: %s", cmd->cmd); 24052419Sjulian return(rtn); 24152419Sjulian} 24252419Sjulian 24352419Sjulian/* 24452419Sjulian * Find a command 24552419Sjulian */ 24652419Sjulianstatic const struct ngcmd * 24752419SjulianFindCommand(const char *string) 24852419Sjulian{ 24952419Sjulian const struct ngcmd *cmd; 25052419Sjulian int k, len, found; 25152419Sjulian 25252419Sjulian if (strcmp(string, "?") == 0) 25352419Sjulian string = "help"; 25452419Sjulian for (k = 0, found = -1; cmds[k]; k++) { 25552419Sjulian cmd = cmds[k]; 25652419Sjulian len = strcspn(cmd->cmd, WHITESPACE); 25752419Sjulian if (len > strlen(string)) 25852419Sjulian len = strlen(string); 25952419Sjulian if (!strncasecmp(string, cmd->cmd, len)) { 26052419Sjulian if (found != -1) { 26152419Sjulian warnx("\"%s\": ambiguous command", string); 26252419Sjulian return(NULL); 26352419Sjulian } 26452419Sjulian found = k; 26552419Sjulian } 26652419Sjulian } 26752419Sjulian if (found == -1) { 26852419Sjulian warnx("\"%s\": unknown command", string); 26952419Sjulian return(NULL); 27052419Sjulian } 27152419Sjulian return(cmds[found]); 27252419Sjulian} 27352419Sjulian 27452419Sjulian/* 27552419Sjulian * ReadCmd() 27652419Sjulian */ 27752419Sjulianstatic int 27852419SjulianReadCmd(int ac, char **av) 27952419Sjulian{ 28052419Sjulian FILE *fp; 28152419Sjulian int rtn; 28252419Sjulian 28352419Sjulian /* Open file */ 28452419Sjulian switch (ac) { 28552419Sjulian case 2: 28652419Sjulian if ((fp = fopen(av[1], "r")) == NULL) 28752419Sjulian warn("%s", av[1]); 28852419Sjulian return(CMDRTN_ERROR); 28952419Sjulian default: 29052419Sjulian return(CMDRTN_USAGE); 29152419Sjulian } 29252419Sjulian 29352419Sjulian /* Process it */ 29452419Sjulian rtn = ReadFile(fp); 29552419Sjulian fclose(fp); 29652419Sjulian return(rtn); 29752419Sjulian} 29852419Sjulian 29952419Sjulian/* 30052419Sjulian * HelpCmd() 30152419Sjulian */ 30252419Sjulianstatic int 30352419SjulianHelpCmd(int ac, char **av) 30452419Sjulian{ 30552419Sjulian const struct ngcmd *cmd; 30652419Sjulian int k; 30752419Sjulian 30852419Sjulian switch (ac) { 30952419Sjulian case 0: 31052419Sjulian case 1: 31152419Sjulian /* Show all commands */ 31252419Sjulian printf("Available commands:\n"); 31352419Sjulian for (k = 0; cmds[k] != NULL; k++) { 31452419Sjulian char *s, buf[100]; 31552419Sjulian 31652419Sjulian cmd = cmds[k]; 31752419Sjulian snprintf(buf, sizeof(buf), "%s", cmd->cmd); 31852419Sjulian for (s = buf; *s != '\0' && !isspace(*s); s++); 31952419Sjulian *s = '\0'; 32052419Sjulian printf(" %-10s %s\n", buf, cmd->desc); 32152419Sjulian } 32252419Sjulian return(CMDRTN_OK); 32352419Sjulian default: 32452419Sjulian /* Show help on a specific command */ 32552419Sjulian if ((cmd = FindCommand(av[1])) != NULL) { 32652419Sjulian printf("Usage: %s\n", cmd->cmd); 32752419Sjulian printf("Summary: %s\n", cmd->desc); 32852419Sjulian if (cmd->help != NULL) { 32952419Sjulian const char *s; 33052419Sjulian char buf[65]; 33152419Sjulian int tot, len, done; 33252419Sjulian 33352419Sjulian printf("Description:\n"); 33452419Sjulian for (s = cmd->help; *s != '\0'; s += len) { 33552419Sjulian while (isspace(*s)) 33652419Sjulian s++; 33752419Sjulian tot = snprintf(buf, 33852419Sjulian sizeof(buf), "%s", s); 33952419Sjulian len = strlen(buf); 34052419Sjulian done = len == tot; 34152419Sjulian if (!done) { 34252419Sjulian while (len > 0 34352419Sjulian && !isspace(buf[len-1])) 34452419Sjulian buf[--len] = '\0'; 34552419Sjulian } 34652419Sjulian printf(" %s\n", buf); 34752419Sjulian } 34852419Sjulian } 34952419Sjulian } 35052419Sjulian } 35152419Sjulian return(CMDRTN_OK); 35252419Sjulian} 35352419Sjulian 35452419Sjulian/* 35552419Sjulian * QuitCmd() 35652419Sjulian */ 35752419Sjulianstatic int 35852419SjulianQuitCmd(int ac, char **av) 35952419Sjulian{ 36052419Sjulian return(CMDRTN_QUIT); 36152419Sjulian} 36252419Sjulian 36352419Sjulian/* 36452419Sjulian * Usage() 36552419Sjulian */ 36652419Sjulianstatic void 36752419SjulianUsage(const char *msg) 36852419Sjulian{ 36952419Sjulian if (msg) 37052419Sjulian warnx("%s", msg); 37152419Sjulian errx(EX_USAGE, "usage: ngctl [-d] [-f file] [-n name] [command ...]"); 37252419Sjulian} 37352419Sjulian 374