/* * command.c * * Written by Toshiharu OHNO * Copyright (c) 1993, Internet Initiative Japan, Inc. All rights reserved. * See ``COPYRIGHT.iij'' * * Rewritten by Archie Cobbs * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved. * See ``COPYRIGHT.whistle'' */ #include "ppp.h" #include "command.h" #include "ccp.h" #include "iface.h" #include "radius.h" #include "bund.h" #include "link.h" #include "lcp.h" #include "ipcp.h" #include "ip.h" #include "devices.h" #include "netgraph.h" #include "custom.h" /* * DEFINITIONS */ struct layer { const char *name; void (*opener)(void); void (*closer)(void); const char *desc; }; typedef struct layer *Layer; #define DEFAULT_OPEN_LAYER "iface" /* * INTERNAL FUNCTIONS */ /* Commands */ static int ShowVersion(int ac, char *av[], void *arg); static int ShowLayers(int ac, char *av[], void *arg); static int ShowTypes(int ac, char *av[], void *arg); static int ShowEvents(int ac, char *av[], void *arg); static int OpenCommand(int ac, char *av[], void *arg); static int CloseCommand(int ac, char *av[], void *arg); static int LoadCommand(int ac, char *av[], void *arg); static int ExitCommand(int ac, char *av[], void *arg); static int QuitCommand(int ac, char *av[], void *arg); static int NullCommand(int ac, char *av[], void *arg); static int HelpCommand(int ac, char *av[], void *arg); static int SetLoginCommand(int ac, char *av[], void *arg); static int SetDebugCommand(int ac, char *av[], void *arg); /* Other stuff */ static int DoCommandTab(CmdTab cmdlist, int ac, char *av[]); static const char *FindCommand(CmdTab cmds, char* str, CmdTab *cp, int complain); static Layer GetLayer(const char *name); /* * INTERNAL VARIABLES */ static int exitflag; static const struct cmdtab ShowCommands[] = { { "bundle [name]", "Bundle status", BundStat, AdmitBund, NULL }, { "ccp", "CCP status", CcpStat, AdmitBund, NULL }, { "ecp", "ECP status", EcpStat, AdmitBund, NULL }, { "events", "Current events", ShowEvents, NULL, NULL }, { "ipcp", "IPCP status", IpcpStat, AdmitBund, NULL }, { "iface", "Interface status", IfaceStat, NULL, NULL }, { "routes", "IP routing table", IpShowRoutes, NULL, NULL }, { "layers", "Layers to open/close", ShowLayers, NULL, NULL }, { "link", "Link status", LinkStat, AdmitBund, NULL }, { "radius", "radius status", RadStat, AdmitBund, NULL }, { "lcp", "LCP status", LcpStat, AdmitBund, NULL }, { "mem", "Memory map", MemStat, NULL, NULL }, { "mp", "Multi-link status", MpStat, AdmitBund, NULL }, { "types", "Supported device types", ShowTypes, NULL, NULL }, { "version", "Version string", ShowVersion, NULL, NULL }, { NULL }, }; static const struct cmdtab SetCommands[] = { { "bundle ...", "Bundle specific stuff", CMD_SUBMENU, AdmitBund, (void *) BundSetCmds }, { "link ...", "Link specific stuff", CMD_SUBMENU, AdmitBund, (void *) LinkSetCmds }, { "iface ...", "Interface specific stuff", CMD_SUBMENU, AdmitBund, (void *) IfaceSetCmds }, { "ipcp ...", "IPCP specific stuff", CMD_SUBMENU, AdmitBund, (void *) IpcpSetCmds }, { "ccp ...", "CCP specific stuff", CMD_SUBMENU, AdmitBund, (void *) CcpSetCmds }, { "ecp ...", "ECP specific stuff", CMD_SUBMENU, AdmitBund, (void *) EcpSetCmds }, { "radius ...", "Set radius configuration", CMD_SUBMENU, AdmitBund, (void *) RadiusSetCmds }, { "login [authname]", "Set/clear console password", SetLoginCommand, NULL, NULL }, { "debug level", "Set netgraph debug level", SetDebugCommand, NULL, NULL }, #define _WANT_DEVICE_CMDS #include "devices.h" { NULL }, }; static const struct cmdtab gCommands[] = { { "new [-i ng#] bundle link ...", "Create new bundle", BundCreateCmd, NULL, NULL }, { "bundle [name]", "Choose/list bundles", BundCommand, AdmitBund, NULL }, { "custom ...", "Custom stuff", CMD_SUBMENU, NULL, (void *) CustomCmds }, { "link name", "Choose link", LinkCommand, AdmitBund, NULL }, { "open [layer]", "Open a layer", OpenCommand, AdmitBund, NULL }, { "close [layer]", "Close a layer", CloseCommand, AdmitBund, NULL }, { "load label", "Read from config file", LoadCommand, NULL, NULL }, { "set ...", "Set parameters", CMD_SUBMENU, NULL, (void *) SetCommands }, { "show ...", "Show status", CMD_SUBMENU, NULL, (void *) ShowCommands }, { "exit", "Exit console", ExitCommand, NULL, NULL }, { "null", "Do nothing", NullCommand, NULL, NULL }, { "log [+/-opt ...]", "Set/view log options", LogCommand, NULL, NULL }, { "quit", "Quit program", QuitCommand, NULL, NULL }, { "help ...", "Help on any command", HelpCommand, NULL, NULL }, { NULL }, }; /* * Layers */ struct layer gLayers[] = { { "iface", IfaceOpen, IfaceClose, "System interface" }, { "ipcp", IpcpOpen, IpcpClose, "IPCP: IP control protocol" }, { "ccp", CcpOpen, CcpClose, "CCP: compression ctrl prot." }, { "ecp", EcpOpen, EcpClose, "ECP: encryption ctrl prot." }, { "bund", BundOpen, BundClose, "Multilink bundle" }, { "lcp", LcpOpen, LcpClose, "LCP: link control protocol" }, { "phys", PhysOpen, PhysClose, "Physical link layer" }, }; #define NUM_LAYERS (sizeof(gLayers) / sizeof(*gLayers)) /* * DoCommand() * * Executes command. Returns TRUE if user wants to quit. */ int DoCommand(int ac, char *av[]) { exitflag = FALSE; DoCommandTab(gCommands, ac, av); return(exitflag); } /* * DoCommandTab() * * Execute command from given command menu */ static int DoCommandTab(CmdTab cmdlist, int ac, char *av[]) { CmdTab cmd; int rtn = 0; /* Huh? */ if (ac <= 0) return(-1); /* Find command */ if (FindCommand(cmdlist, av[0], &cmd, cmdlist == gCommands)) return(-1); /* Check command admissibility */ if (cmd->admit && !(cmd->admit)(cmd)) return(0); /* Find command and either execute or recurse into a submenu */ if (cmd->func == CMD_SUBMENU) rtn = DoCommandTab((CmdTab) cmd->arg, ac - 1, av + 1); else if (cmd->func == CMD_UNIMPL) Log(LG_ERR, ("mpd: %s: unimplemented command", av[0])); else rtn = (cmd->func)(ac - 1, av + 1, cmd->arg); /* Bad usage? */ if (cmdlist == gCommands && rtn < 0) HelpCommand(ac, av, NULL); return(rtn); } /* * FindCommand() */ static const char * FindCommand(CmdTab cmds, char *str, CmdTab *cmdp, int complain) { int found, nmatch; int len = strlen(str); const char *fmt; for (nmatch = 0, found = NULL; cmds->name; cmds++) { if (cmds->name && !strncmp(str, cmds->name, len)) { *cmdp = cmds; nmatch++; } } switch (nmatch) { case 0: fmt = "%s: unknown command. Try \"help\"."; if (complain) Log(LG_ERR, (fmt, str)); return(fmt); case 1: return(NULL); default: fmt = "%s: ambiguous command"; if (complain) Log(LG_ERR, (fmt, str)); return(fmt); } } /********** COMMANDS **********/ /* * HelpCommand() */ static int HelpCommand(int ac, char *av[], void *arg) { int depth; CmdTab menu, cmd; char *mark, *mark_save; const char *errfmt; char buf[100]; for (mark = buf, depth = *buf = 0, menu = gCommands; depth < ac; depth++, menu = (CmdTab) cmd->arg) { if ((errfmt = FindCommand(menu, av[depth], &cmd, FALSE))) { int k; for (*buf = k = 0; k <= depth; k++) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s%c", av[k], k == depth ? '\0' : ' '); Log(LG_ERR, (errfmt, buf)); return(0); } sprintf(mark, depth ? " %s" : "%s", cmd->name); mark_save = mark; if ((mark = strchr(mark + 1, ' ')) == NULL) mark = mark_save + strlen(mark_save); if (cmd->func != CMD_SUBMENU) { printf("Usage: %s\n", buf); return(0); } } /* Show list of available commands in this submenu */ *mark = 0; if (!*buf) printf("Available commands:\n"); else printf("Commands available under \"%s\":\n", buf); for (cmd = menu; cmd->name; cmd++) { snprintf(buf, sizeof(buf), "%s", cmd->name); if ((mark = strchr(buf, ' '))) *mark = 0; printf(" %-9s: %-20s%c", buf, cmd->desc, ((cmd - menu) & 1)? '\n' : '\t'); } if ((cmd - menu) & 1) printf("\n"); return(0); } /* * SetLoginCommand() */ static int SetLoginCommand(int ac, char *av[], void *arg) { switch (ac) { case 0: *gLoginAuthName = 0; break; case 1: snprintf(gLoginAuthName, sizeof(gLoginAuthName), "%s", av[0]); break; default: return(-1); } return(0); } /* * SetDebugCommand() */ static int SetDebugCommand(int ac, char *av[], void *arg) { switch (ac) { case 1: NgSetDebug(atoi(av[0])); break; default: return(-1); } return(0); } /* * ShowVersion() */ static int ShowVersion(int ac, char *av[], void *arg) { printf("MPD version: %s\n", gVersion); return(0); } /* * ShowEvents() */ static int ShowEvents(int ac, char *av[], void *arg) { EventDump("mpd events"); return(0); } /* * ExitCommand() */ static int ExitCommand(int ac, char *av[], void *arg) { exitflag = TRUE; return(0); } /* * QuitCommand() */ static int QuitCommand(int ac, char *av[], void *arg) { RecordLinkUpDownReason(NULL, 0, STR_QUIT, NULL); DoExit(EX_NORMAL); return(0); } /* * NullCommand() */ static int NullCommand(int ac, char *av[], void *arg) { return(0); } /* * LoadCommand() */ static int LoadCommand(int ac, char *av[], void *arg) { if (ac != 1) Log(LG_ERR, ("Usage: load system")); else { if (ReadFile(gConfigFile, *av, DoCommand) < 0) Log(LG_ERR, ("mpd: entry \"%s\" not found in %s", *av, gConfigFile)); } return(0); } /* * OpenCommand() */ static int OpenCommand(int ac, char *av[], void *arg) { Layer layer; const char *name; switch (ac) { case 0: name = DEFAULT_OPEN_LAYER; break; case 1: name = av[0]; break; default: return(-1); } if ((layer = GetLayer(name)) != NULL) (*layer->opener)(); return(0); } /* * CloseCommand() */ static int CloseCommand(int ac, char *av[], void *arg) { Layer layer; const char *name; switch (ac) { case 0: name = DEFAULT_OPEN_LAYER; break; case 1: name = av[0]; break; default: return(-1); } if ((layer = GetLayer(name)) != NULL) (*layer->closer)(); return(0); } /* * GetLayer() */ static Layer GetLayer(const char *name) { int k, found; if (name == NULL) name = "iface"; for (found = -1, k = 0; k < NUM_LAYERS; k++) { if (!strncasecmp(name, gLayers[k].name, strlen(name))) { if (found > 0) { Log(LG_ERR, ("%s: ambiguous", name)); return(NULL); } else found = k; } } if (found < 0) { Log(LG_ERR, ("mpd: unknown layer \"%s\": try \"show layers\"", name)); return(NULL); } return(&gLayers[found]); } /* * ShowLayers() */ static int ShowLayers(int ac, char *av[], void *arg) { int k; printf("\tName\t\tDescription\n" "\t----\t\t-----------\n"); for (k = 0; k < NUM_LAYERS; k++) printf("\t%s\t\t%s\n", gLayers[k].name, gLayers[k].desc); return(0); } /* * ShowTypes() */ static int ShowTypes(int ac, char *av[], void *arg) { PhysType pt; int k; printf("Supported device types:\n\t"); for (k = 0; (pt = gPhysTypes[k]); k++) printf(" %s", pt->name); printf("\n"); return(0); } /* * AdmitBund() */ int AdmitBund(CmdTab cmd) { if (!bund) { Log(LG_ERR, ("mpd: no bundles defined")); return(FALSE); } return(TRUE); } /* * AdmitDev() */ int AdmitDev(CmdTab cmd) { if (!AdmitBund(cmd)) return(FALSE); if (lnk->phys->type == NULL) { Log(LG_ERR, ("mpd: type of link \"%s\" is unspecified", lnk->name)); return(FALSE); } if (!strcmp(cmd->name, lnk->phys->type->name)) { Log(LG_ERR, ("mpd: link \"%s\" is type %s, not %s", lnk->name, lnk->phys->type->name, cmd->name)); return(FALSE); } return(TRUE); }