--- libaitcli/src/aitcli.c 2013/10/08 09:38:55 1.8.2.5 +++ libaitcli/src/aitcli.c 2016/08/18 09:12:00 1.14.2.1 @@ -3,7 +3,7 @@ * by Michael Pounov * * $Author: misho $ -* $Id: aitcli.c,v 1.8.2.5 2013/10/08 09:38:55 misho Exp $ +* $Id: aitcli.c,v 1.14.2.1 2016/08/18 09:12:00 misho Exp $ * ************************************************************************** The ELWIX and AITNET software is distributed under the following @@ -106,7 +106,7 @@ printfEOL(linebuffer_t * __restrict buf, int len, int } write(buf->line_out, buf->line_buf, len == -1 ? - buf->line_eol - buf->line_bol: len); + buf->line_eol - buf->line_bol : len); } } @@ -154,7 +154,8 @@ bufCHAR(int idx, void * __restrict cli_buffer) memcpy(buf->line_buf + pos, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len); buf->line_buf[buf->line_len - 1] = 0; - write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len); + if (buf->line_prompt) + write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len); if (buf->line_mode == LINEMODE_INS) { write(buf->line_out, (const u_char*) buf->line_buf + pos + buf->line_keys[idx].key_len, @@ -426,7 +427,7 @@ bufComp(int idx, void * __restrict cli_buffer) if (i) { SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) { - if (cmd->cmd_level == buf->line_level && + if (cmd->cmd_level & (1 << buf->line_level) && !strncmp(cmd->cmd_name, items[0], strlen(items[0]))) { if (strncmp(cmd->cmd_name, CLI_CMD_SEP, @@ -452,7 +453,7 @@ bufComp(int idx, void * __restrict cli_buffer) } else { /* we on 0 position of prompt, show commands for this level */ SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) { - if (cmd->cmd_level == buf->line_level) + if (cmd->cmd_level & (1 << buf->line_level)) if (strncmp(cmd->cmd_name, CLI_CMD_SEP, strlen(CLI_CMD_SEP))) { j++; c = cmd; @@ -506,7 +507,24 @@ bufHelp(int idx, void * __restrict cli_buffer) return RETCODE_OK; } +static int +bufEndNode(int idx, void * __restrict cli_buffer) +{ + linebuffer_t *buf = cli_buffer; + if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY) + return RETCODE_ERR; + + if (buf->line_level > 0) { + printfNL(cli_buffer, 0); + buf->line_level--; + cli_Printf(buf, "Enter to config level %d\n", buf->line_level); + } + + return bufCLR(idx, cli_buffer); +} + + /* * cli_Printf() - Send message to CLI session * @@ -586,7 +604,7 @@ cli_BindKey(bindkey_t * __restrict key, linebuffer_t * * * @cli_buffer = CLI buffer * @csCmd = Command name - * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ... + * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels * @funcCmd = Callback function when user call command * @csInfo = Inline information for command * @csHelp = Help line when call help @@ -627,7 +645,7 @@ cli_addCommand(linebuffer_t * __restrict cli_buffer, c * * @cli_buffer = CLI buffer * @csCmd = Command name - * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ... + * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels * return: RETCODE_ERR error, RETCODE_OK ok */ int @@ -657,7 +675,7 @@ cli_delCommand(linebuffer_t * __restrict cli_buffer, c * * @cli_buffer = CLI buffer * @csCmd = Command name - * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ... + * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels * @funcCmd = Callback function when user call command * @csInfo = Inline information for command * @csHelp = Help line when call help @@ -676,10 +694,11 @@ cli_updCommand(linebuffer_t * __restrict cli_buffer, c return RETCODE_ERR; } - SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) - if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) { - ret = 1; - + SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) + if ((!cmd->cmd_level || cmd->cmd_level == cliLevel) && + !strcmp(cmd->cmd_name, csCmd)) { + if (!cmd->cmd_level) + cmd->cmd_level = cliLevel; if (funcCmd) cmd->cmd_func = funcCmd; if (csInfo) @@ -1009,9 +1028,16 @@ cliInit(int fin, int fout, const char *prompt) memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1)); /* add helper functions */ - cli_addCommand(cli_buffer, "exit", 0, cli_Cmd_Exit, "exit ", "Exit from console"); - cli_addCommand(cli_buffer, "help", 0, cli_Cmd_Help, "help [command] ", "Help screen"); - cli_addCommand(cli_buffer, "-------", 0, NULL, "-------------------------", NULL); + cli_addCommand(cli_buffer, "exit", 1, cli_Cmd_Exit, "exit ", "Exit from console"); + cli_addCommand(cli_buffer, "help", -1, cli_Cmd_Help, "help [command] ", "Help screen"); + cli_addCommand(cli_buffer, "-------", -1, NULL, "-------------------------", NULL); + cli_addCommand(cli_buffer, "where", -1, cli_Cmd_WhereAmI, "where ", + "Query current level of console"); + cli_addCommand(cli_buffer, "top", -1, cli_Cmd_Top, "top ", "Top level of console"); + cli_addCommand(cli_buffer, "end", -1, cli_Cmd_End, "end ", "End level of console"); + cli_addCommand(cli_buffer, "config", -1, cli_Cmd_Config, "config ", + "Config next level of console"); + cli_addCommand(cli_buffer, "-------", -1, NULL, "-------------------------", NULL); /* fill key bindings */ /* ascii chars & ctrl+chars */ @@ -1025,7 +1051,7 @@ cliInit(int fin, int fout, const char *prompt) keys[i].key_func = bufEOL; if (cli_buffer->line_prompt && (i == *K_CTRL_H || i == *K_BACKSPACE)) keys[i].key_func = bufBS; - if (cli_buffer->line_prompt && i == *K_CTRL_C) + if (i == *K_CTRL_C) keys[i].key_func = bufCLR; if (cli_buffer->line_prompt && i == *K_CTRL_A) keys[i].key_func = bufBEGIN; @@ -1033,6 +1059,8 @@ cliInit(int fin, int fout, const char *prompt) keys[i].key_func = bufEND; if (cli_buffer->line_prompt && i == *K_TAB) keys[i].key_func = bufComp; + if (i == *K_CTRL_Z) + keys[i].key_func = bufEndNode; if (i >= *K_SPACE && i < *K_BACKSPACE) keys[i].key_func = bufCHAR; if (i > *K_BACKSPACE && i < 0xff) @@ -1239,12 +1267,13 @@ cliInitLine(linebuffer_t * __restrict cli_buffer) * cliReadLine() - Read line from opened CLI session * * @cli_buffer = CLI buffer + * @timeout = Session timeout (-1 infinit) * return: NULL if error or !=NULL readed line, must be e_free after use! */ char * -cliReadLine(linebuffer_t * __restrict cli_buffer) +cliReadLine(linebuffer_t * __restrict cli_buffer, int timeout) { - int code, readLen; + int code, readLen, ret; register int i; struct pollfd fds; char buf[BUFSIZ], *str = NULL; @@ -1252,7 +1281,8 @@ cliReadLine(linebuffer_t * __restrict cli_buffer) if (!cli_buffer) { cli_SetErr(EINVAL, "Invalid input parameters ..."); return NULL; - } + } else if (timeout > 0) + timeout *= 1000; /* convert from sec to ms */ memset(&fds, 0, sizeof fds); fds.fd = cli_buffer->line_in; @@ -1260,24 +1290,25 @@ cliReadLine(linebuffer_t * __restrict cli_buffer) printfCR(cli_buffer, 1); while (42) { - if (poll(&fds, 1, -1) < 1) { - LOGERR; + if ((ret = poll(&fds, 1, timeout)) < 1) { + if (!ret) { + cli_buffer->line_kill = 1; + if (str) { + e_free(str); + str = NULL; + } + } else + LOGERR; return str; } memset(buf, 0, sizeof buf); readLen = read(cli_buffer->line_in, buf, BUFSIZ); - if (readLen == -1) { - LOGERR; - return str; + if (readLen < 1) { + if (readLen) + LOGERR; + return NULL; } - if (!readLen) { - if (cli_buffer->line_buf) - str = e_strdup(cli_buffer->line_buf); - else - cli_SetErr(EPIPE, "Unknown state ..."); - return str; - } recheck: for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--) @@ -1316,13 +1347,15 @@ recheck: * @cli_buffer = CLI buffer * @csHistFile = History file name * @sock = client socket + * @timeout = Session timeout (-1 infinit) * return: RETCODE_ERR error, RETCODE_OK ok */ int -cliNetLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, int sock) +cliNetLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, + int sock, int timeout) { u_char buf[BUFSIZ]; - int pid, stat, pty, r, s, alen, flg, attrlen = 0, ret = 0; + int pid, stat, pty, s, alen, flg, attrlen = 0, ret = 0; fd_set fds; struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 }; struct telnetAttrs *a, Attr[10]; @@ -1338,7 +1371,7 @@ cliNetLoop(linebuffer_t * __restrict cli_buffer, const } else close(sock); - ret = cliLoop(cli_buffer, csHistFile) < 0 ? 1 : 0; + ret = cliLoop(cli_buffer, csHistFile, timeout) < 0 ? 1 : 0; cliEnd(cli_buffer); _exit(ret); @@ -1367,7 +1400,7 @@ cliNetLoop(linebuffer_t * __restrict cli_buffer, const break; } - r = FD_ISSET(sock, &fds) ? sock : pty; + FD_ISSET(sock, &fds) ? sock : pty; s = FD_ISSET(sock, &fds) ? pty : sock; if (FD_ISSET(sock, &fds)) { @@ -1407,8 +1440,9 @@ cliNetLoop(linebuffer_t * __restrict cli_buffer, const if (FD_ISSET(pty, &fds)) { memset(buf, 0, BUFSIZ); - if ((ret = read(pty, buf, BUFSIZ)) == -1) { - LOGERR; + if ((ret = read(pty, buf, BUFSIZ)) < 1) { + if (ret) + LOGERR; break; } @@ -1431,10 +1465,11 @@ cliNetLoop(linebuffer_t * __restrict cli_buffer, const * * @cli_buffer = CLI buffer * @csHistFile = History file name + * @timeout = Session timeout (-1 infinit) * return: RETCODE_ERR error, RETCODE_OK ok */ int -cliLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile) +cliLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, int timeout) { char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS]; register int i; @@ -1448,7 +1483,7 @@ cliLoop(linebuffer_t * __restrict cli_buffer, const ch return RETCODE_ERR; do { - line = cliReadLine(cli_buffer); + line = cliReadLine(cli_buffer, timeout); if (!line) { printfNL(cli_buffer, 0); break; @@ -1469,6 +1504,8 @@ cliLoop(linebuffer_t * __restrict cli_buffer, const ch // exec_cmd ... i = 0; SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) { + if (!(cmd->cmd_level & (1 << cli_buffer->line_level))) + continue; if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0]))) break; else @@ -1476,11 +1513,13 @@ cliLoop(linebuffer_t * __restrict cli_buffer, const ch } if (!cmd) { - cli_Printf(cli_buffer, "\nCommand '%s' not found!\n", items[0]); + cli_Printf(cli_buffer, "%sCommand '%s' not found!\n", + cli_buffer->line_prompt ? "\n" : "", items[0]); ret = -1; } else if (cmd->cmd_func) { - cli_Printf(cli_buffer, "\n"); + if (cli_buffer->line_prompt) + cli_Printf(cli_buffer, "\n"); ret = cmd->cmd_func(cli_buffer, cli_buffer->line_level, items); } else { @@ -1492,7 +1531,7 @@ cliLoop(linebuffer_t * __restrict cli_buffer, const ch cli_freeLine(cli_buffer); cli_resetHistory(cli_buffer); e_free(line); - } while (ret < 1); + } while (cli_buffer->line_kill || ret < 1); cli_saveHistory(cli_buffer, csHistFile, HISTORY_LINES); return ret;