1 2 /* 3 * main.c 4 * 5 * Copyright (c) 1996-1999 Whistle Communications, Inc. 6 * All rights reserved. 7 * 8 * Subject to the following obligations and disclaimer of warranty, use and 9 * redistribution of this software, in source or object code forms, with or 10 * without modifications are expressly permitted by Whistle Communications; 11 * provided, however, that: 12 * 1. Any and all reproductions of the source or object code must include the 13 * copyright notice above and the following disclaimer of warranties; and 14 * 2. No rights are granted, in any manner or form, to use Whistle 15 * Communications, Inc. trademarks, including the mark "WHISTLE 16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17 * such appears in the above copyright notice or in the software. 18 * 19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35 * OF SUCH DAMAGE. 36 * 37 * $FreeBSD$ 38 */ 39 40 #include "ngctl.h" 41 42 #define PROMPT "+ " 43 #define MAX_ARGS 512 44 #define WHITESPACE " \t\r\n\v\f" 45 46 /* Internal functions */ 47 static int ReadFile(FILE *fp); 48 static int DoParseCommand(char *line); 49 static int DoCommand(int ac, char **av); 50 static int DoInteractive(void); 51 static const struct ngcmd *FindCommand(const char *string); 52 static void Usage(const char *msg); 53 static int ReadCmd(int ac, char **av); 54 static int HelpCmd(int ac, char **av); 55 static int QuitCmd(int ac, char **av); 56 57 /* List of commands */ 58 static const struct ngcmd *const cmds[] = { 59 &connect_cmd, 60 &debug_cmd, 61 &help_cmd, 62 &list_cmd, 63 &mkpeer_cmd, 64 &name_cmd, 65 &read_cmd, 66 &rmhook_cmd, 67 &show_cmd, 68 &shutdown_cmd, 69 &status_cmd, 70 &types_cmd, 71 &quit_cmd, 72 NULL 73 }; 74 75 /* Commands defined in this file */ 76 const struct ngcmd read_cmd = { 77 ReadCmd, 78 "read <filename>", 79 "Read and execute commands from a file", 80 NULL 81 }; 82 const struct ngcmd help_cmd = { 83 HelpCmd, 84 "help [command]", 85 "Show command summary or get more help on a specific command", 86 NULL 87 }; 88 const struct ngcmd quit_cmd = { 89 QuitCmd, 90 "quit", 91 "Exit program", 92 NULL 93 }; 94 95 /* Our control and data sockets */ 96 int csock, dsock; 97 98 /* 99 * main() 100 */ 101 int 102 main(int ac, char *av[]) 103 { 104 char name[NG_NODELEN + 1]; 105 int interactive = isatty(0) && isatty(1); 106 FILE *fp = NULL; 107 int ch, rtn = 0; 108 109 /* Set default node name */ 110 snprintf(name, sizeof(name), "ngctl%d", getpid()); 111 112 /* Parse command line */ 113 while ((ch = getopt(ac, av, "df:n:")) != EOF) { 114 switch (ch) { 115 case 'd': 116 NgSetDebug(NgSetDebug(-1) + 1); 117 break; 118 case 'f': 119 if (strcmp(optarg, "-") == 0) 120 fp = stdin; 121 else if ((fp = fopen(optarg, "r")) == NULL) 122 err(EX_NOINPUT, "%s", optarg); 123 break; 124 case 'n': 125 snprintf(name, sizeof(name), "%s", optarg); 126 break; 127 case '?': 128 default: 129 Usage((char *)NULL); 130 break; 131 } 132 } 133 ac -= optind; 134 av += optind; 135 136 /* Create a new socket node */ 137 if (NgMkSockNode(name, &csock, &dsock) < 0) 138 err(EX_OSERR, "can't create node"); 139 140 /* Do commands as requested */ 141 if (ac == 0) { 142 if (fp != NULL) { 143 rtn = ReadFile(fp); 144 } else if (interactive) { 145 rtn = DoInteractive(); 146 } else 147 Usage("no command specified"); 148 } else { 149 rtn = DoCommand(ac, av); 150 } 151 152 /* Convert command return code into system exit code */ 153 switch (rtn) { 154 case CMDRTN_OK: 155 case CMDRTN_QUIT: 156 rtn = 0; 157 break; 158 case CMDRTN_USAGE: 159 rtn = EX_USAGE; 160 break; 161 case CMDRTN_ERROR: 162 rtn = EX_OSERR; 163 break; 164 } 165 return(rtn); 166 } 167 168 /* 169 * Process commands from a file 170 */ 171 static int 172 ReadFile(FILE *fp) 173 { 174 char line[LINE_MAX]; 175 int num, rtn; 176 177 for (num = 1; fgets(line, sizeof(line), fp) != NULL; num++) { 178 if (*line == '#') 179 continue; 180 if ((rtn = DoParseCommand(line)) != 0) { 181 warnx("line %d: error in file", num); 182 return(rtn); 183 } 184 } 185 return(CMDRTN_OK); 186 } 187 188 /* 189 * Interactive mode 190 */ 191 static int 192 DoInteractive(void) 193 { 194 char buf[LINE_MAX]; 195 196 /* Read commands from stdin */ 197 (*help_cmd.func)(0, NULL); 198 do { 199 printf("%s", PROMPT); 200 if (fgets(buf, sizeof(buf), stdin) == NULL) 201 break; 202 fflush(stdout); 203 } while (DoParseCommand(buf) != CMDRTN_QUIT); 204 return(CMDRTN_QUIT); 205 } 206 207 /* 208 * Parse a command line and execute the command 209 */ 210 static int 211 DoParseCommand(char *line) 212 { 213 char *av[MAX_ARGS]; 214 int ac; 215 216 /* Parse line */ 217 for (ac = 0, av[0] = strtok(line, WHITESPACE); 218 ac < MAX_ARGS - 1 && av[ac]; 219 av[++ac] = strtok(NULL, WHITESPACE)); 220 221 /* Do command */ 222 return(DoCommand(ac, av)); 223 } 224 225 /* 226 * Execute the command 227 */ 228 static int 229 DoCommand(int ac, char **av) 230 { 231 const struct ngcmd *cmd; 232 int rtn; 233 234 if (ac == 0 || *av[0] == 0) 235 return(CMDRTN_OK); 236 if ((cmd = FindCommand(av[0])) == NULL) 237 return(CMDRTN_ERROR); 238 if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE) 239 warnx("usage: %s", cmd->cmd); 240 return(rtn); 241 } 242 243 /* 244 * Find a command 245 */ 246 static const struct ngcmd * 247 FindCommand(const char *string) 248 { 249 const struct ngcmd *cmd; 250 int k, len, found; 251 252 if (strcmp(string, "?") == 0) 253 string = "help"; 254 for (k = 0, found = -1; cmds[k]; k++) { 255 cmd = cmds[k]; 256 len = strcspn(cmd->cmd, WHITESPACE); 257 if (len > strlen(string)) 258 len = strlen(string); 259 if (!strncasecmp(string, cmd->cmd, len)) { 260 if (found != -1) { 261 warnx("\"%s\": ambiguous command", string); 262 return(NULL); 263 } 264 found = k; 265 } 266 } 267 if (found == -1) { 268 warnx("\"%s\": unknown command", string); 269 return(NULL); 270 } 271 return(cmds[found]); 272 } 273 274 /* 275 * ReadCmd() 276 */ 277 static int 278 ReadCmd(int ac, char **av) 279 { 280 FILE *fp; 281 int rtn; 282 283 /* Open file */ 284 switch (ac) { 285 case 2: 286 if ((fp = fopen(av[1], "r")) == NULL) 287 warn("%s", av[1]); 288 return(CMDRTN_ERROR); 289 default: 290 return(CMDRTN_USAGE); 291 } 292 293 /* Process it */ 294 rtn = ReadFile(fp); 295 fclose(fp); 296 return(rtn); 297 } 298 299 /* 300 * HelpCmd() 301 */ 302 static int 303 HelpCmd(int ac, char **av) 304 { 305 const struct ngcmd *cmd; 306 int k; 307 308 switch (ac) { 309 case 0: 310 case 1: 311 /* Show all commands */ 312 printf("Available commands:\n"); 313 for (k = 0; cmds[k] != NULL; k++) { 314 char *s, buf[100]; 315 316 cmd = cmds[k]; 317 snprintf(buf, sizeof(buf), "%s", cmd->cmd); 318 for (s = buf; *s != '\0' && !isspace(*s); s++); 319 *s = '\0'; 320 printf(" %-10s %s\n", buf, cmd->desc); 321 } 322 return(CMDRTN_OK); 323 default: 324 /* Show help on a specific command */ 325 if ((cmd = FindCommand(av[1])) != NULL) { 326 printf("Usage: %s\n", cmd->cmd); 327 printf("Summary: %s\n", cmd->desc); 328 if (cmd->help != NULL) { 329 const char *s; 330 char buf[65]; 331 int tot, len, done; 332 333 printf("Description:\n"); 334 for (s = cmd->help; *s != '\0'; s += len) { 335 while (isspace(*s)) 336 s++; 337 tot = snprintf(buf, 338 sizeof(buf), "%s", s); 339 len = strlen(buf); 340 done = len == tot; 341 if (!done) { 342 while (len > 0 343 && !isspace(buf[len-1])) 344 buf[--len] = '\0'; 345 } 346 printf(" %s\n", buf); 347 } 348 } 349 } 350 } 351 return(CMDRTN_OK); 352 } 353 354 /* 355 * QuitCmd() 356 */ 357 static int 358 QuitCmd(int ac, char **av) 359 { 360 return(CMDRTN_QUIT); 361 } 362 363 /* 364 * Usage() 365 */ 366 static void 367 Usage(const char *msg) 368 { 369 if (msg) 370 warnx("%s", msg); 371 errx(EX_USAGE, "usage: ngctl [-d] [-f file] [-n name] [command ...]"); 372 } 373 374