File:  [ELWIX - Embedded LightWeight unIX -] / libaitcli / src / aitcli.c
Revision 1.8.2.2: download - view: text, annotated - select for diffs - revision graph
Tue Oct 8 09:18:45 2013 UTC (10 years, 10 months ago) by misho
Branches: cli3_3
Diff to: branchpoint 1.8: preferred, unified
add forgotten level support

    1: /*************************************************************************
    2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
    3: *  by Michael Pounov <misho@openbsd-bg.org>
    4: *
    5: * $Author: misho $
    6: * $Id: aitcli.c,v 1.8.2.2 2013/10/08 09:18:45 misho Exp $
    7: *
    8: **************************************************************************
    9: The ELWIX and AITNET software is distributed under the following
   10: terms:
   11: 
   12: All of the documentation and software included in the ELWIX and AITNET
   13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
   14: 
   15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
   16: 	by Michael Pounov <misho@elwix.org>.  All rights reserved.
   17: 
   18: Redistribution and use in source and binary forms, with or without
   19: modification, are permitted provided that the following conditions
   20: are met:
   21: 1. Redistributions of source code must retain the above copyright
   22:    notice, this list of conditions and the following disclaimer.
   23: 2. Redistributions in binary form must reproduce the above copyright
   24:    notice, this list of conditions and the following disclaimer in the
   25:    documentation and/or other materials provided with the distribution.
   26: 3. All advertising materials mentioning features or use of this software
   27:    must display the following acknowledgement:
   28: This product includes software developed by Michael Pounov <misho@elwix.org>
   29: ELWIX - Embedded LightWeight unIX and its contributors.
   30: 4. Neither the name of AITNET nor the names of its contributors
   31:    may be used to endorse or promote products derived from this software
   32:    without specific prior written permission.
   33: 
   34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
   35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   37: ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   44: SUCH DAMAGE.
   45: */
   46: #include "global.h"
   47: #include "cli.h"
   48: 
   49: 
   50: #pragma GCC visibility push(hidden)
   51: 
   52: int cli_Errno;
   53: char cli_Error[STRSIZ];
   54: 
   55: #pragma GCC visibility pop
   56: 
   57: // cli_GetErrno() Get error code of last operation
   58: int
   59: cli_GetErrno()
   60: {
   61: 	return cli_Errno;
   62: }
   63: 
   64: // cli_GetError() Get error text of last operation
   65: const char *
   66: cli_GetError()
   67: {
   68: 	return cli_Error;
   69: }
   70: 
   71: // cli_SetErr() Set error to variables for internal use!!!
   72: void
   73: cli_SetErr(int eno, char *estr, ...)
   74: {
   75: 	va_list lst;
   76: 
   77: 	cli_Errno = eno;
   78: 	memset(cli_Error, 0, sizeof cli_Error);
   79: 	va_start(lst, estr);
   80: 	vsnprintf(cli_Error, sizeof cli_Error, estr, lst);
   81: 	va_end(lst);
   82: }
   83: 
   84: // ------------------------------------------------------------
   85: 
   86: static inline void
   87: clrscrEOL(linebuffer_t * __restrict buf)
   88: {
   89: 	register int i;
   90: 
   91: 	if (buf && buf->line_prompt) {
   92: 		write(buf->line_out, K_CR, 1);
   93: 
   94: 		for (i = 0; i < buf->line_len; i++)
   95: 			write(buf->line_out, K_SPACE, 1);
   96: 
   97: 		buf->line_level ^= buf->line_level;
   98: 	}
   99: }
  100: 
  101: static inline void
  102: printfEOL(linebuffer_t * __restrict buf, int len, int prompt)
  103: {
  104: 	if (buf) {
  105: 		if (prompt && buf->line_prompt) {
  106: 			write(buf->line_out, K_CR, 1);
  107: 			write(buf->line_out, buf->line_prompt, buf->line_bol);
  108: 			buf->line_level ^= buf->line_level;
  109: 		}
  110: 
  111: 		write(buf->line_out, buf->line_buf, len == -1 ? 
  112: 				buf->line_eol - buf->line_bol: len);
  113: 	}
  114: }
  115: 
  116: static inline void
  117: printfCR(linebuffer_t * __restrict buf, int prompt)
  118: {
  119: 	if (buf && prompt && buf->line_prompt) {
  120: 		write(buf->line_out, K_CR, 1);
  121: 		write(buf->line_out, buf->line_prompt, buf->line_bol);
  122: 	}
  123: }
  124: 
  125: static inline void
  126: printfNL(linebuffer_t * __restrict buf, int prompt)
  127: {
  128: 	if (buf) {
  129: 		write(buf->line_out, K_ENTER, 1);
  130: 
  131: 		if (prompt) {
  132: 			if (prompt && buf->line_prompt)
  133: 				write(buf->line_out, buf->line_prompt, buf->line_bol);
  134: 			buf->line_level ^= buf->line_level;
  135: 		}
  136: 	}
  137: }
  138: 
  139: // ------------------------------------------------------------
  140: 
  141: static int
  142: bufCHAR(int idx, void * __restrict cli_buffer)
  143: {
  144: 	linebuffer_t *buf = cli_buffer;
  145: 	int pos;
  146: 
  147: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  148: 		return RETCODE_ERR;
  149: 
  150: 	pos = buf->line_eol - buf->line_bol;
  151: 
  152: 	if (buf->line_mode == LINEMODE_INS)
  153: 		memmove(buf->line_buf + pos + buf->line_keys[idx].key_len, buf->line_buf + pos, 
  154: 				buf->line_len - buf->line_eol);
  155: 	if (buf->line_mode == LINEMODE_INS || buf->line_eol == buf->line_len - 1)
  156: 		buf->line_len += buf->line_keys[idx].key_len;
  157: 	buf->line_eol += buf->line_keys[idx].key_len;
  158: 
  159: 	memcpy(buf->line_buf + pos, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
  160: 	buf->line_buf[buf->line_len - 1] = 0;
  161: 
  162: 	write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
  163: 
  164: 	if (buf->line_mode == LINEMODE_INS) {
  165: 		write(buf->line_out, (const u_char*) buf->line_buf + pos + buf->line_keys[idx].key_len, 
  166: 				buf->line_len - buf->line_eol);
  167: 		printfEOL(buf, -1, 1);
  168: 	}
  169: 	return RETCODE_OK;
  170: }
  171: 
  172: static int
  173: bufEOL(int idx, void * __restrict cli_buffer)
  174: {
  175: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  176: 		return RETCODE_ERR;
  177: 
  178: 	printfCR(cli_buffer, 1);
  179: 	return RETCODE_EOL;
  180: }
  181: 
  182: static int
  183: bufEOF(int idx, void * __restrict cli_buffer)
  184: {
  185: 	/*
  186: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  187: 		return RETCODE_ERR;
  188: 	*/
  189: 
  190: 	return RETCODE_EOF;
  191: }
  192: 
  193: static int
  194: bufUP(int idx, void * __restrict cli_buffer)
  195: {
  196: 	linebuffer_t *buf = cli_buffer;
  197: 	int pos;
  198: 
  199: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  200: 		return RETCODE_ERR;
  201: 
  202: 	if (!buf->line_h)
  203: 		buf->line_h = TAILQ_FIRST(&buf->line_history);
  204: 	else
  205: 		buf->line_h = TAILQ_NEXT(buf->line_h, hist_next);
  206: 	if (!buf->line_h)
  207: 		return RETCODE_OK;
  208: 
  209: 	clrscrEOL(buf);
  210: 	cli_freeLine(buf);
  211: 
  212: 	pos = buf->line_eol - buf->line_bol;
  213: 
  214: 	buf->line_len += buf->line_h->hist_len;
  215: 	buf->line_eol += buf->line_h->hist_len;
  216: 
  217: 	memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
  218: 	buf->line_buf[buf->line_len - 1] = 0;
  219: 
  220: 	printfEOL(buf, -1, 1);
  221: 	return RETCODE_OK;
  222: }
  223: 
  224: static int
  225: bufDOWN(int idx, void * __restrict cli_buffer)
  226: {
  227: 	linebuffer_t *buf = cli_buffer;
  228: 	int pos;
  229: 
  230: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  231: 		return RETCODE_ERR;
  232: 
  233: 	if (!buf->line_h)
  234: 		buf->line_h = TAILQ_LAST(&buf->line_history, tqHistoryHead);
  235: 	else
  236: 		buf->line_h = TAILQ_PREV(buf->line_h, tqHistoryHead, hist_next);
  237: 	if (!buf->line_h)
  238: 		return RETCODE_OK;
  239: 
  240: 	clrscrEOL(buf);
  241: 	cli_freeLine(buf);
  242: 
  243: 	pos = buf->line_eol - buf->line_bol;
  244: 
  245: 	buf->line_len += buf->line_h->hist_len;
  246: 	buf->line_eol += buf->line_h->hist_len;
  247: 
  248: 	memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
  249: 	buf->line_buf[buf->line_len - 1] = 0;
  250: 
  251: 	printfEOL(buf, -1, 1);
  252: 	return RETCODE_OK;
  253: }
  254: 
  255: static int
  256: bufCLR(int idx, void * __restrict cli_buffer)
  257: {
  258: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  259: 		return RETCODE_ERR;
  260: 
  261: 	clrscrEOL(cli_buffer);
  262: 	cli_freeLine(cli_buffer);
  263: 
  264: 	printfCR(cli_buffer, 1);
  265: 	return RETCODE_OK;
  266: }
  267: 
  268: static int
  269: bufBS(int idx, void * __restrict cli_buffer)
  270: {
  271: 	linebuffer_t *buf = cli_buffer;
  272: 
  273: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  274: 		return RETCODE_ERR;
  275: 
  276: 	if (buf->line_bol < buf->line_eol) {
  277: 		clrscrEOL(buf);
  278: 
  279: 		buf->line_eol--;
  280: 		buf->line_len--;
  281: 		memmove(buf->line_buf + buf->line_eol - buf->line_bol, 
  282: 				buf->line_buf + buf->line_eol - buf->line_bol + 1, 
  283: 				buf->line_len - buf->line_eol);
  284: 		buf->line_buf[buf->line_len - 1] = 0;
  285: 
  286: 		printfEOL(buf, buf->line_len - 1, 1);
  287: 		printfEOL(buf, -1, 1);
  288: 	}
  289: 
  290: 	return RETCODE_OK;
  291: }
  292: 
  293: static int
  294: bufBTAB(int idx, void * __restrict cli_buffer)
  295: {
  296: 	linebuffer_t *buf = cli_buffer;
  297: 
  298: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  299: 		return RETCODE_ERR;
  300: 
  301: 	if (buf->line_bol < buf->line_eol) {
  302: 		clrscrEOL(buf);
  303: 
  304: 		buf->line_len = buf->line_eol - buf->line_bol + 1;
  305: 		buf->line_buf[buf->line_len - 1] = 0;
  306: 
  307: 		printfEOL(buf, -1, 1);
  308: 	}
  309: 
  310: 	return RETCODE_OK;
  311: }
  312: 
  313: static int
  314: bufMODE(int idx, void * __restrict cli_buffer)
  315: {
  316: 	linebuffer_t *buf = cli_buffer;
  317: 
  318: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  319: 		return RETCODE_ERR;
  320: 
  321: 	buf->line_mode = !buf->line_mode ? LINEMODE_OVER : LINEMODE_INS;
  322: 	return RETCODE_OK;
  323: }
  324: 
  325: static int
  326: bufBEGIN(int idx, void * __restrict cli_buffer)
  327: {
  328: 	linebuffer_t *buf = cli_buffer;
  329: 
  330: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  331: 		return RETCODE_ERR;
  332: 
  333: 	buf->line_eol = buf->line_bol;
  334: 
  335: 	printfCR(buf, 1);
  336: 	return RETCODE_OK;
  337: }
  338: 
  339: static int
  340: bufEND(int idx, void * __restrict cli_buffer)
  341: {
  342: 	linebuffer_t *buf = cli_buffer;
  343: 
  344: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  345: 		return RETCODE_ERR;
  346: 
  347: 	buf->line_eol = buf->line_len - 1;
  348: 
  349: 	printfEOL(buf, -1, 1);
  350: 	return RETCODE_OK;
  351: }
  352: 
  353: static int
  354: bufLEFT(int idx, void * __restrict cli_buffer)
  355: {
  356: 	linebuffer_t *buf = cli_buffer;
  357: 
  358: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  359: 		return RETCODE_ERR;
  360: 
  361: 	if (buf->line_bol < buf->line_eol)
  362: 		printfEOL(buf, --buf->line_eol - buf->line_bol, 1);
  363: 
  364: 	return RETCODE_OK;
  365: }
  366: 
  367: static int
  368: bufRIGHT(int idx, void * __restrict cli_buffer)
  369: {
  370: 	linebuffer_t *buf = cli_buffer;
  371: 
  372: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  373: 		return RETCODE_ERR;
  374: 
  375: 	if (buf->line_eol < buf->line_len - 1)
  376: 		printfEOL(buf, ++buf->line_eol - buf->line_bol, 1);
  377: 
  378: 	return RETCODE_OK;
  379: }
  380: 
  381: static int
  382: bufDEL(int idx, void * __restrict cli_buffer)
  383: {
  384: 	linebuffer_t *buf = cli_buffer;
  385: 
  386: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  387: 		return RETCODE_ERR;
  388: 
  389: 	clrscrEOL(buf);
  390: 
  391: 	buf->line_len--;
  392: 	memmove(buf->line_buf + buf->line_eol - buf->line_bol, 
  393: 			buf->line_buf + buf->line_eol - buf->line_bol + 1, 
  394: 			buf->line_len - buf->line_eol);
  395: 	buf->line_buf[buf->line_len - 1] = 0;
  396: 
  397: 	printfEOL(buf, buf->line_len - 1, 1);
  398: 	printfEOL(buf, -1, 1);
  399: 
  400: 	return RETCODE_OK;
  401: }
  402: 
  403: static int
  404: bufComp(int idx, void * __restrict cli_buffer)
  405: {
  406: 	linebuffer_t *buf = cli_buffer;
  407: 	char *str, *s, **app, *items[MAX_PROMPT_ITEMS], szLine[STRSIZ];
  408: 	register int i, j;
  409: 	struct tagCommand *cmd, *c;
  410: 	int pos, ret = RETCODE_OK;
  411: 
  412: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  413: 		return RETCODE_ERR;
  414: 
  415: 	str = e_strdup(buf->line_buf);
  416: 	if (!str)
  417: 		return RETCODE_ERR;
  418: 	else {
  419: 		s = str;
  420: 		str_Trim(s);
  421: 	}
  422: 
  423: 	i = j = 0;
  424: 	c = NULL;
  425: 	memset(szLine, 0, STRSIZ);
  426: 	if (*s) {
  427: 		memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
  428: 		for (app = items, i = 0; app < items + MAX_PROMPT_ITEMS - 1 && 
  429: 				(*app = strsep(&s, " \t")); 
  430: 			 	*app ? i++ : i, *app ? app++ : app);
  431: 
  432: 		if (i) {
  433: 			SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
  434: 				if (cmd->cmd_level == buf->line_level && 
  435: 						!strncmp(cmd->cmd_name, items[0], 
  436: 							strlen(items[0]))) {
  437: 					if (strncmp(cmd->cmd_name, CLI_CMD_SEP, 
  438: 								strlen(CLI_CMD_SEP))) {
  439: 						j++;
  440: 						c = cmd;
  441: 						strlcat(szLine, " ", STRSIZ);
  442: 						strlcat(szLine, cmd->cmd_name, STRSIZ);
  443: 						buf->line_level++;
  444: 					}
  445: 				}
  446: 			}
  447: 
  448: 			if (i > 1 && c) {
  449: 				/* we are on argument of command and has complition info */
  450: 				j++;	// always must be j > 1 ;) for arguments
  451: 				strlcpy(szLine, c->cmd_info, STRSIZ);
  452: 			}
  453: 		} else {
  454: 			/* we have valid char but i == 0, this case is illegal */
  455: 			ret = RETCODE_ERR;
  456: 			goto endcomp;
  457: 		}
  458: 	} else {
  459: 		/* we on 0 position of prompt, show commands for this level */
  460: 		SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
  461: 			if (cmd->cmd_level == buf->line_level)
  462: 				if (strncmp(cmd->cmd_name, CLI_CMD_SEP, strlen(CLI_CMD_SEP))) {
  463: 					j++;
  464: 					c = cmd;
  465: 					strlcat(szLine, " ", STRSIZ);
  466: 					strlcat(szLine, cmd->cmd_name, STRSIZ);
  467: 					buf->line_level++;
  468: 				}
  469: 		}
  470: 	}
  471: 
  472: 	/* completion show actions ... */
  473: 	if (j > 1 && c) {
  474: 		printfNL(buf, 0);
  475: 		write(buf->line_out, szLine, strlen(szLine));
  476: 		printfNL(buf, 1);
  477: 		printfEOL(buf, buf->line_len - 1, 1);
  478: 		printfEOL(buf, -1, 1);
  479: 	}
  480: 	if (j == 1 && c) {
  481: 		clrscrEOL(buf);
  482: 		cli_freeLine(buf);
  483: 
  484: 		pos = buf->line_eol - buf->line_bol;
  485: 
  486: 		buf->line_len += c->cmd_len + 1;
  487: 		buf->line_eol += c->cmd_len + 1;
  488: 
  489: 		memcpy(buf->line_buf + pos, c->cmd_name, c->cmd_len);
  490: 		buf->line_buf[pos + c->cmd_len] = (u_char) *K_SPACE;
  491: 		buf->line_buf[buf->line_len - 1] = 0;
  492: 
  493: 		printfEOL(buf, -1, 1);
  494: 	}
  495: 
  496: endcomp:
  497: 	e_free(str);
  498: 	return ret;
  499: }
  500: 
  501: static int
  502: bufHelp(int idx, void * __restrict cli_buffer)
  503: {
  504: 	linebuffer_t *buf = cli_buffer;
  505: 
  506: 	if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
  507: 		return RETCODE_ERR;
  508: 
  509: 	cli_Cmd_Help(buf, -1, NULL);
  510: 
  511: 	printfEOL(buf, buf->line_len - 1, 1);
  512: 	printfEOL(buf, -1, 1);
  513: 	return RETCODE_OK;
  514: }
  515: 
  516: 
  517: /*
  518:  * cli_Printf() - Send message to CLI session
  519:  *
  520:  * @cli_buffer = CLI buffer
  521:  * @fmt = printf format string
  522:  * @... = arguments defined in fmt
  523:  * return: none
  524: */
  525: void
  526: cli_Printf(linebuffer_t * __restrict cli_buffer, char *fmt, ...)
  527: {
  528: 	va_list lst;
  529: 	FILE *f;
  530: 
  531: 	if (fmt) {
  532: 		f = fdopen(cli_buffer->line_out, "a");
  533: 		if (!f) {
  534: 			LOGERR;
  535: 			return;
  536: 		}
  537: 
  538: 		va_start(lst, fmt);
  539: 		vfprintf(f, fmt, lst);
  540: 		va_end(lst);
  541: 	} else
  542: 		cli_SetErr(EINVAL, "Invalid input parameters ...");
  543: }
  544: 
  545: /*
  546:  * cli_PrintHelp() - Print help screen
  547:  *
  548:  * @cli_buffer = CLI buffer
  549:  * return: none
  550: */
  551: void
  552: cli_PrintHelp(linebuffer_t * __restrict cli_buffer)
  553: {
  554: 	if (cli_buffer) {
  555: 		bufHelp(0, cli_buffer);
  556: 		clrscrEOL(cli_buffer);
  557: 	} else
  558: 		cli_SetErr(EINVAL, "Invalid input parameters ...");
  559: }
  560: 
  561: 
  562: /*
  563:  * cli_BindKey() - Bind function to key
  564:  *
  565:  * @key = key structure
  566:  * @cli_buffer = CLI buffer
  567:  * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position
  568: */
  569: int
  570: cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict cli_buffer)
  571: {
  572: 	register int i;
  573: 
  574: 	if (!key || !cli_buffer) {
  575: 		cli_SetErr(EINVAL, "Invalid input parameters ...");
  576: 		return RETCODE_ERR;
  577: 	}
  578: 
  579: 	for (i = 0; i < MAX_BINDKEY; i++)
  580: 		if (key->key_len == cli_buffer->line_keys[i].key_len && 
  581: 				!memcmp(key->key_ch, cli_buffer->line_keys[i].key_ch, 
  582: 					key->key_len)) {
  583: 			cli_buffer->line_keys[i].key_func = key->key_func;
  584: 			return i;
  585: 		}
  586: 
  587: 	return RETCODE_OK;
  588: }
  589: 
  590: 
  591: /*
  592:  * cli_addCommand() - Add command to CLI session
  593:  *
  594:  * @cli_buffer = CLI buffer
  595:  * @csCmd = Command name
  596:  * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
  597:  * @funcCmd = Callback function when user call command
  598:  * @csInfo = Inline information for command
  599:  * @csHelp = Help line when call help
  600:  * return: RETCODE_ERR error, RETCODE_OK ok
  601: */
  602: int
  603: cli_addCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, 
  604: 		int cliLevel, cmd_func_t funcCmd, 
  605: 		const char *csInfo, const char *csHelp)
  606: {
  607: 	struct tagCommand *cmd;
  608: 
  609: 	if (!cli_buffer || !csCmd) {
  610: 		cli_SetErr(EINVAL, "Invalid input parameters ...");
  611: 		return RETCODE_ERR;
  612: 	}
  613: 
  614: 	cmd = e_malloc(sizeof(struct tagCommand));
  615: 	if (!cmd) {
  616: 		LOGERR;
  617: 		return RETCODE_ERR;
  618: 	} else
  619: 		memset(cmd, 0, sizeof(struct tagCommand));
  620: 
  621: 	cmd->cmd_level = cliLevel;
  622: 	cmd->cmd_func = funcCmd;
  623: 	cmd->cmd_len = strlcpy(cmd->cmd_name, csCmd, STRSIZ);
  624: 	if (csInfo)
  625: 		strlcpy(cmd->cmd_info, csInfo, STRSIZ);
  626: 	if (csHelp)
  627: 		strlcpy(cmd->cmd_help, csHelp, STRSIZ);
  628: 	SLIST_INSERT_HEAD(&cli_buffer->line_cmds, cmd, cmd_next);
  629: 	return RETCODE_OK;
  630: }
  631: 
  632: /*
  633:  * cli_delCommand() - Delete command from CLI session
  634:  *
  635:  * @cli_buffer = CLI buffer
  636:  * @csCmd = Command name
  637:  * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
  638:  * return: RETCODE_ERR error, RETCODE_OK ok
  639: */
  640: int
  641: cli_delCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, int cliLevel)
  642: {
  643: 	struct tagCommand *cmd;
  644: 	int ret = RETCODE_OK;
  645: 
  646: 	if (!cli_buffer || !csCmd) {
  647: 		cli_SetErr(EINVAL, "Invalid input parameters ...");
  648: 		return RETCODE_ERR;
  649: 	}
  650: 
  651: 	SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) 
  652: 		if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
  653: 			ret = 1;
  654: 			SLIST_REMOVE(&cli_buffer->line_cmds, cmd, tagCommand, cmd_next);
  655: 			e_free(cmd);
  656: 			break;
  657: 		}
  658: 
  659: 	return ret;
  660: }
  661: 
  662: /*
  663:  * cli_updCommand() - Update command in CLI session
  664:  *
  665:  * @cli_buffer = CLI buffer
  666:  * @csCmd = Command name
  667:  * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
  668:  * @funcCmd = Callback function when user call command
  669:  * @csInfo = Inline information for command
  670:  * @csHelp = Help line when call help
  671:  * return: RETCODE_ERR error, RETCODE_OK ok
  672: */
  673: int
  674: cli_updCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, 
  675: 		int cliLevel, cmd_func_t funcCmd, 
  676: 		const char *csInfo, const char *csHelp)
  677: {
  678: 	struct tagCommand *cmd;
  679: 	int ret = RETCODE_OK;
  680: 
  681: 	if (!cli_buffer || !csCmd) {
  682: 		cli_SetErr(EINVAL, "Invalid input parameters ...");
  683: 		return RETCODE_ERR;
  684: 	}
  685: 
  686: 	SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) 
  687: 		if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
  688: 			ret = 1;
  689: 
  690: 			if (funcCmd)
  691: 				cmd->cmd_func = funcCmd;
  692: 			if (csInfo)
  693: 				strlcpy(cmd->cmd_info, csInfo, STRSIZ);
  694: 			if (csHelp)
  695: 				strlcpy(cmd->cmd_help, csHelp, STRSIZ);
  696: 
  697: 			break;
  698: 		}
  699: 
  700: 	return ret;
  701: }
  702: 
  703: 
  704: /*
  705:  * cli_addHistory() - Add line to history
  706:  *
  707:  * @cli_buffer = CLI buffer
  708:  * @str = Add custom text or if NULL use readed line from CLI buffer
  709:  * return: RETCODE_ERR error, RETCODE_OK ok
  710: */
  711: int
  712: cli_addHistory(linebuffer_t * __restrict cli_buffer, const char * __restrict str)
  713: {
  714: 	struct tagHistory *h;
  715: 
  716: 	if (!cli_buffer) {
  717: 		cli_SetErr(EINVAL, "Invalid input parameters ...");
  718: 		return RETCODE_ERR;
  719: 	}
  720: 
  721: 	if (!(h = e_malloc(sizeof(struct tagHistory)))) {
  722: 		LOGERR;
  723: 		return RETCODE_ERR;
  724: 	} else
  725: 		memset(h, 0, sizeof(struct tagHistory));
  726: 
  727: 	if (str) {
  728: 		if (!*str) {
  729: 			e_free(h);
  730: 			return RETCODE_OK;
  731: 		}
  732: 
  733: 		h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
  734: 	} else {
  735: 		if (!*cli_buffer->line_buf || cli_buffer->line_len < 2) {
  736: 			e_free(h);
  737: 			return RETCODE_OK;
  738: 		}
  739: 
  740: 		memcpy(h->hist_line, cli_buffer->line_buf, (h->hist_len = cli_buffer->line_len));
  741: 		str_Trim(h->hist_line);
  742: 		h->hist_len = strlen(h->hist_line);
  743: 	}
  744: 
  745: 	TAILQ_INSERT_HEAD(&cli_buffer->line_history, h, hist_next);
  746: 	return h->hist_len;
  747: }
  748: 
  749: /*
  750:  * cli_saveHistory() - Save history to file
  751:  *
  752:  * @cli_buffer = CLI buffer
  753:  * @histfile = History filename, if NULL will be use default name
  754:  * @lines = Maximum history lines to save
  755:  * return: RETCODE_ERR error, RETCODE_OK ok
  756: */
  757: int
  758: cli_saveHistory(linebuffer_t * __restrict cli_buffer, const char *histfile, int lines)
  759: {
  760: 	FILE *f;
  761: 	mode_t mode;
  762: 	char szFName[MAXPATHLEN];
  763: 	struct tagHistory *h;
  764: 
  765: 	if (!cli_buffer) {
  766: 		cli_SetErr(EINVAL, "Invalid input parameters ...");
  767: 		return RETCODE_ERR;
  768: 	}
  769: 	if (!histfile)
  770: 		strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
  771: 	else
  772: 		strlcpy(szFName, histfile, MAXPATHLEN);
  773: 
  774: 	mode = umask(0177);
  775: 	f = fopen(szFName, "w");
  776: 	if (!f) {
  777: 		LOGERR;
  778: 		return RETCODE_ERR;
  779: 	}
  780: 
  781: 	TAILQ_FOREACH(h, &cli_buffer->line_history, hist_next) {
  782: 		fprintf(f, "%s\n", h->hist_line);
  783: 
  784: 		if (lines)
  785: 			lines--;
  786: 		else
  787: 			break;
  788: 	}
  789: 
  790: 	fclose(f);
  791: 	umask(mode);
  792: 
  793: 	return RETCODE_OK;
  794: }
  795: 
  796: /*
  797:  * cli_loadHistory() - Load history from file
  798:  *
  799:  * @cli_buffer = CLI buffer
  800:  * @histfile = History filename, if NULL will be use default name
  801:  * return: RETCODE_ERR error, RETCODE_OK ok
  802: */
  803: int
  804: cli_loadHistory(linebuffer_t * __restrict cli_buffer, const char *histfile)
  805: {
  806: 	FILE *f;
  807: 	char szFName[MAXPATHLEN], buf[BUFSIZ];
  808: 	struct tagHistory *h;
  809: 
  810: 	if (!cli_buffer) {
  811: 		cli_SetErr(EINVAL, "Invalid input parameters ...");
  812: 		return RETCODE_ERR;
  813: 	}
  814: 	if (!histfile)
  815: 		strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
  816: 	else
  817: 		strlcpy(szFName, histfile, MAXPATHLEN);
  818: 
  819: 	f = fopen(szFName, "r");
  820: 	if (!f)
  821: 		return RETCODE_OK;
  822: 
  823: 	while (fgets(buf, BUFSIZ, f)) {
  824: 		if (!*buf || *buf == '#')
  825: 			continue;
  826: 		else
  827: 			str_Trim(buf);
  828: 
  829: 		if (!(h = e_malloc(sizeof(struct tagHistory)))) {
  830: 			LOGERR;
  831: 			fclose(f);
  832: 			return RETCODE_ERR;
  833: 		} else
  834: 			memset(h, 0, sizeof(struct tagHistory));
  835: 
  836: 		h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
  837: 		TAILQ_INSERT_TAIL(&cli_buffer->line_history, h, hist_next);
  838: 	}
  839: 
  840: 	fclose(f);
  841: 
  842: 	return RETCODE_OK;
  843: }
  844: 
  845: /*
  846:  * cli_resetHistory() - Reset history search in CLI session
  847:  *
  848:  * @cli_buffer = CLI buffer
  849:  * return: none
  850: */
  851: void
  852: cli_resetHistory(linebuffer_t * __restrict cli_buffer)
  853: {
  854: 	cli_buffer->line_h = NULL;
  855: }
  856: 
  857: 
  858: /*
  859:  * cli_freeLine() - Clear entire line
  860:  *
  861:  * @cli_buffer = CLI buffer
  862:  * return: RETCODE_ERR error, RETCODE_OK ok
  863: */
  864: int
  865: cli_freeLine(linebuffer_t * __restrict cli_buffer)
  866: {
  867: 	int code = RETCODE_ERR;
  868: 
  869: 	if (cli_buffer) {
  870: 		if (cli_buffer->line_buf)
  871: 			e_free(cli_buffer->line_buf);
  872: 
  873: 		cli_buffer->line_buf = e_malloc(BUFSIZ);
  874: 		if (cli_buffer->line_buf) {
  875: 			memset(cli_buffer->line_buf, 0, BUFSIZ);
  876: 			cli_buffer->line_eol = cli_buffer->line_bol;
  877: 			cli_buffer->line_len = 1 + cli_buffer->line_eol;
  878: 
  879: 			code = RETCODE_OK;
  880: 		} else
  881: 			LOGERR;
  882: 	} else
  883: 		cli_SetErr(EINVAL, "Invalid input parameters ...");
  884: 
  885: 	return code;
  886: }
  887: 
  888: /*
  889:  * cli_setPrompt() - Set new prompt for CLI session
  890:  *
  891:  * @cli_buffer = CLI buffer
  892:  * @prompt = new text for prompt or if NULL disable prompt
  893:  * return: none
  894: */
  895: void
  896: cli_setPrompt(linebuffer_t * __restrict cli_buffer, const char *prompt)
  897: {
  898: 	if (cli_buffer) {
  899: 		if (cli_buffer->line_prompt) {
  900: 			e_free(cli_buffer->line_prompt);
  901: 			cli_buffer->line_prompt = NULL;
  902: 			cli_buffer->line_bol = 0;
  903: 		}
  904: 
  905: 		if (prompt) {
  906: 			cli_buffer->line_prompt = e_strdup(prompt);
  907: 			if (cli_buffer->line_prompt) {
  908: 				cli_buffer->line_bol = strlen(cli_buffer->line_prompt);
  909: 				cli_buffer->line_eol = cli_buffer->line_bol;
  910: 				cli_buffer->line_len = 1 + cli_buffer->line_eol;
  911: 			} else
  912: 				LOGERR;
  913: 		}
  914: 	} else
  915: 		cli_SetErr(EINVAL, "Invalid input parameters ...");
  916: }
  917: 
  918: 
  919: /*
  920:  * cliEnd() - Clear data, Free resources and close CLI session
  921:  *
  922:  * @cli_buffer = CLI buffer
  923:  * return: RETCODE_ERR error, RETCODE_OK ok
  924: */
  925: void
  926: cliEnd(linebuffer_t * __restrict cli_buffer)
  927: {
  928: 	struct tagHistory *h;
  929: 	struct tagCommand *c;
  930: 
  931: 	if (cli_buffer) {
  932: 		while ((c = SLIST_FIRST(&cli_buffer->line_cmds))) {
  933: 			SLIST_REMOVE_HEAD(&cli_buffer->line_cmds, cmd_next);
  934: 			e_free(c);
  935: 		}
  936: 		while ((h = TAILQ_FIRST(&cli_buffer->line_history))) {
  937: 			TAILQ_REMOVE(&cli_buffer->line_history, h, hist_next);
  938: 			e_free(h);
  939: 		}
  940: 
  941: 		if (cli_buffer->line_prompt)
  942: 			e_free(cli_buffer->line_prompt);
  943: 
  944: 		if (cli_buffer->line_keys)
  945: 			e_free(cli_buffer->line_keys);
  946: 		if (cli_buffer->line_buf)
  947: 			e_free(cli_buffer->line_buf);
  948: 
  949: 		e_free(cli_buffer);
  950: 		cli_buffer = NULL;
  951: 	} else
  952: 		cli_SetErr(EINVAL, "Invalid input parameters ...");
  953: }
  954: 
  955: /*
  956:  * cliInit() - Start CLI session, allocate memory for resources and bind keys
  957:  *
  958:  * @fin = Input device handle
  959:  * @fout = Output device handle
  960:  * @prompt = text for prompt, if NULL disable prompt
  961:  * return: NULL if error or !=NULL CLI buffer
  962: */
  963: linebuffer_t *
  964: cliInit(int fin, int fout, const char *prompt)
  965: {
  966: 	linebuffer_t *cli_buffer;
  967: 	bindkey_t *keys;
  968: 	register int i;
  969: 
  970: 	/* init buffer */
  971: 	cli_buffer = e_malloc(sizeof(linebuffer_t));
  972: 	if (!cli_buffer) {
  973: 		LOGERR;
  974: 		return NULL;
  975: 	} else {
  976: 		memset(cli_buffer, 0, sizeof(linebuffer_t));
  977: 
  978: 		cli_buffer->line_in = fin;
  979: 		cli_buffer->line_out = fout;
  980: 
  981: 		TAILQ_INIT(&cli_buffer->line_history);
  982: 		SLIST_INIT(&cli_buffer->line_cmds);
  983: 
  984: 		if (prompt) {
  985: 			cli_buffer->line_prompt = e_strdup(prompt);
  986: 			if (!cli_buffer->line_prompt) {
  987: 				LOGERR;
  988: 				e_free(cli_buffer);
  989: 				return NULL;
  990: 			} else
  991: 				cli_buffer->line_eol = cli_buffer->line_bol = 
  992: 					strlen(cli_buffer->line_prompt);
  993: 		} else
  994: 			cli_buffer->line_mode = LINEMODE_OVER;
  995: 	}
  996: 	cli_buffer->line_buf = e_malloc(BUFSIZ);
  997: 	if (!cli_buffer->line_buf) {
  998: 		LOGERR;
  999: 		if (cli_buffer->line_prompt)
 1000: 			e_free(cli_buffer->line_prompt);
 1001: 		e_free(cli_buffer);
 1002: 		return NULL;
 1003: 	} else {
 1004: 		memset(cli_buffer->line_buf, 0, BUFSIZ);
 1005: 		cli_buffer->line_len = 1 + cli_buffer->line_eol;
 1006: 	}
 1007: 	keys = e_calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
 1008: 	if (!keys) {
 1009: 		LOGERR;
 1010: 		if (cli_buffer->line_prompt)
 1011: 			e_free(cli_buffer->line_prompt);
 1012: 		e_free(cli_buffer->line_buf);
 1013: 		e_free(cli_buffer);
 1014: 		return NULL;
 1015: 	} else
 1016: 		memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
 1017: 
 1018: 	/* add helper functions */
 1019: 	cli_addCommand(cli_buffer, "exit", 0, cli_Cmd_Exit, "exit <cr>", "Exit from console");
 1020: 	cli_addCommand(cli_buffer, "help", 0, cli_Cmd_Help, "help [command] <cr>", "Help screen");
 1021: 	cli_addCommand(cli_buffer, "-------", 0, NULL, "-------------------------", NULL);
 1022: 
 1023: 	/* fill key bindings */
 1024: 	/* ascii chars & ctrl+chars */
 1025: 	for (i = 0; i < 256; i++) {
 1026: 		*keys[i].key_ch = (u_char) i;
 1027: 		keys[i].key_len = 1;
 1028: 
 1029: 		if (!i || i == *K_CTRL_D)
 1030: 			keys[i].key_func = bufEOF;
 1031: 		if (i == *K_CTRL_M || i == *K_CTRL_J)
 1032: 			keys[i].key_func = bufEOL;
 1033: 		if (cli_buffer->line_prompt && (i == *K_CTRL_H || i == *K_BACKSPACE))
 1034: 			keys[i].key_func = bufBS;
 1035: 		if (cli_buffer->line_prompt && i == *K_CTRL_C)
 1036: 			keys[i].key_func = bufCLR;
 1037: 		if (cli_buffer->line_prompt && i == *K_CTRL_A)
 1038: 			keys[i].key_func = bufBEGIN;
 1039: 		if (cli_buffer->line_prompt && i == *K_CTRL_E)
 1040: 			keys[i].key_func = bufEND;
 1041: 		if (cli_buffer->line_prompt && i == *K_TAB)
 1042: 			keys[i].key_func = bufComp;
 1043: 		if (i >= *K_SPACE && i < *K_BACKSPACE)
 1044: 			keys[i].key_func = bufCHAR;
 1045: 		if (i > *K_BACKSPACE && i < 0xff)
 1046: 			keys[i].key_func = bufCHAR;
 1047: 		if (cli_buffer->line_prompt && i == '?')
 1048: 			keys[i].key_func = bufHelp;
 1049: 	}
 1050: 	/* alt+chars */
 1051: 	for (i = 256; i < 512; i++) {
 1052: 		keys[i].key_ch[0] = 0x1b;
 1053: 		keys[i].key_ch[1] = (u_char) i - 256;
 1054: 		keys[i].key_len = 2;
 1055: 	}
 1056: 
 1057: 	/* 3 bytes */
 1058: 	keys[i].key_len = sizeof K_F1 - 1;
 1059: 	memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
 1060: 	i++;
 1061: 	keys[i].key_len = sizeof K_F2 - 1;
 1062: 	memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
 1063: 	i++;
 1064: 	keys[i].key_len = sizeof K_F3 - 1;
 1065: 	memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
 1066: 	i++;
 1067: 	keys[i].key_len = sizeof K_F4 - 1;
 1068: 	memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
 1069: 	i++;
 1070: 	keys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
 1071: 	memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
 1072: 	i++;
 1073: 	keys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
 1074: 	memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
 1075: 	i++;
 1076: 	keys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
 1077: 	memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
 1078: 	i++;
 1079: 	keys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
 1080: 	memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
 1081: 	i++;
 1082: 	keys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
 1083: 	memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
 1084: 	i++;
 1085: 	keys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
 1086: 	memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
 1087: 	i++;
 1088: 	keys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
 1089: 	memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
 1090: 	i++;
 1091: 	keys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
 1092: 	memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
 1093: 	i++;
 1094: 	keys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
 1095: 	memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
 1096: 	i++;
 1097: 	keys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
 1098: 	memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
 1099: 	i++;
 1100: 	keys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
 1101: 	memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
 1102: 	i++;
 1103: 	keys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
 1104: 	memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
 1105: 	i++;
 1106: 	keys[i].key_len = sizeof K_CTRL_F1 - 1;
 1107: 	memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
 1108: 	i++;
 1109: 	keys[i].key_len = sizeof K_CTRL_F2 - 1;
 1110: 	memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
 1111: 	i++;
 1112: 	keys[i].key_len = sizeof K_CTRL_F3 - 1;
 1113: 	memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
 1114: 	i++;
 1115: 	keys[i].key_len = sizeof K_CTRL_F4 - 1;
 1116: 	memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
 1117: 	i++;
 1118: 	keys[i].key_len = sizeof K_CTRL_F5 - 1;
 1119: 	memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
 1120: 	i++;
 1121: 	keys[i].key_len = sizeof K_CTRL_F6 - 1;
 1122: 	memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
 1123: 	i++;
 1124: 	keys[i].key_len = sizeof K_CTRL_F7 - 1;
 1125: 	memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
 1126: 	i++;
 1127: 	keys[i].key_len = sizeof K_CTRL_F8 - 1;
 1128: 	memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
 1129: 	i++;
 1130: 	keys[i].key_len = sizeof K_CTRL_F9 - 1;
 1131: 	memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
 1132: 	i++;
 1133: 	keys[i].key_len = sizeof K_CTRL_F10 - 1;
 1134: 	memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
 1135: 	i++;
 1136: 	keys[i].key_len = sizeof K_CTRL_F11 - 1;
 1137: 	memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
 1138: 	i++;
 1139: 	keys[i].key_len = sizeof K_CTRL_F12 - 1;
 1140: 	memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
 1141: 	i++;
 1142: 	keys[i].key_len = sizeof K_HOME - 1;
 1143: 	if (cli_buffer->line_prompt)
 1144: 		keys[i].key_func = bufBEGIN;
 1145: 	memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
 1146: 	i++;
 1147: 	keys[i].key_len = sizeof K_END - 1;
 1148: 	if (cli_buffer->line_prompt)
 1149: 		keys[i].key_func = bufEND;
 1150: 	memcpy(keys[i].key_ch, K_END, keys[i].key_len);
 1151: 	i++;
 1152: 	keys[i].key_len = sizeof K_UP - 1;
 1153: 	if (cli_buffer->line_prompt)
 1154: 		keys[i].key_func = bufUP;
 1155: 	memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
 1156: 	i++;
 1157: 	keys[i].key_len = sizeof K_DOWN - 1;
 1158: 	if (cli_buffer->line_prompt)
 1159: 		keys[i].key_func = bufDOWN;
 1160: 	memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
 1161: 	i++;
 1162: 	keys[i].key_len = sizeof K_RIGHT - 1;
 1163: 	if (cli_buffer->line_prompt)
 1164: 		keys[i].key_func = bufRIGHT;
 1165: 	memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
 1166: 	i++;
 1167: 	keys[i].key_len = sizeof K_LEFT - 1;
 1168: 	if (cli_buffer->line_prompt)
 1169: 		keys[i].key_func = bufLEFT;
 1170: 	memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
 1171: 	i++;
 1172: 	keys[i].key_len = sizeof K_BTAB - 1;
 1173: 	if (cli_buffer->line_prompt)
 1174: 		keys[i].key_func = bufBTAB;
 1175: 	memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
 1176: 	i++;
 1177: 	/* 4 bytes */
 1178: 	keys[i].key_len = sizeof K_INS - 1;
 1179: 	if (cli_buffer->line_prompt)
 1180: 		keys[i].key_func = bufMODE;
 1181: 	memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
 1182: 	i++;
 1183: 	keys[i].key_len = sizeof K_DEL - 1;
 1184: 	if (cli_buffer->line_prompt)
 1185: 		keys[i].key_func = bufDEL;
 1186: 	memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
 1187: 	i++;
 1188: 	keys[i].key_len = sizeof K_PGUP - 1;
 1189: 	memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
 1190: 	i++;
 1191: 	keys[i].key_len = sizeof K_PGDN - 1;
 1192: 	memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
 1193: 	i++;
 1194: 	/* 5 bytes */
 1195: 	keys[i].key_len = sizeof K_F5 - 1;
 1196: 	memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
 1197: 	i++;
 1198: 	keys[i].key_len = sizeof K_F6 - 1;
 1199: 	memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
 1200: 	i++;
 1201: 	keys[i].key_len = sizeof K_F7 - 1;
 1202: 	memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
 1203: 	i++;
 1204: 	keys[i].key_len = sizeof K_F8 - 1;
 1205: 	memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
 1206: 	i++;
 1207: 	keys[i].key_len = sizeof K_F9 - 1;
 1208: 	memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
 1209: 	i++;
 1210: 	keys[i].key_len = sizeof K_F10 - 1;
 1211: 	memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
 1212: 	i++;
 1213: 	keys[i].key_len = sizeof K_F11 - 1;
 1214: 	memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
 1215: 	i++;
 1216: 	keys[i].key_len = sizeof K_F12 - 1;
 1217: 	memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
 1218: 	i++;
 1219: 
 1220: 	cli_buffer->line_keys = keys;
 1221: 	return cli_buffer;
 1222: }
 1223: 
 1224: /*
 1225:  * cliInitLine() - Init CLI input line terminal
 1226:  *
 1227:  * @cli_buffer = CLI buffer
 1228:  * return: none
 1229: */
 1230: int
 1231: cliInitLine(linebuffer_t * __restrict cli_buffer)
 1232: {
 1233: 	struct termios t;
 1234: 
 1235: 	memset(&t, 0, sizeof t);
 1236: 	tcgetattr(cli_buffer->line_in, &t);
 1237: 	t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | 
 1238: 			ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
 1239: 	t.c_iflag |= IGNBRK;
 1240: 	t.c_cc[VMIN] = 1;
 1241: 	t.c_cc[VTIME] = 0;
 1242: 	return tcsetattr(cli_buffer->line_in, TCSANOW, &t);
 1243: }
 1244: 
 1245: /*
 1246:  * cliReadLine() - Read line from opened CLI session
 1247:  *
 1248:  * @cli_buffer = CLI buffer
 1249:  * return: NULL if error or !=NULL readed line, must be e_free after use!
 1250: */
 1251: char *
 1252: cliReadLine(linebuffer_t * __restrict cli_buffer)
 1253: {
 1254: 	int code, readLen;
 1255: 	register int i;
 1256: 	struct pollfd fds;
 1257: 	char buf[BUFSIZ], *str = NULL;
 1258: 
 1259: 	if (!cli_buffer) {
 1260: 		cli_SetErr(EINVAL, "Invalid input parameters ...");
 1261: 		return NULL;
 1262: 	}
 1263: 
 1264: 	memset(&fds, 0, sizeof fds);
 1265: 	fds.fd = cli_buffer->line_in;
 1266: 	fds.events = POLLIN;
 1267: 
 1268: 	printfCR(cli_buffer, 1);
 1269: 	while (42) {
 1270: 		if (poll(&fds, 1, -1) < 1) {
 1271: 			LOGERR;
 1272: 			return str;
 1273: 		}
 1274: 
 1275: 		memset(buf, 0, sizeof buf);
 1276: 		readLen = read(cli_buffer->line_in, buf, BUFSIZ);
 1277: 		if (readLen == -1) {
 1278: 			LOGERR;
 1279: 			return str;
 1280: 		}
 1281: 		if (!readLen) {
 1282: 			if (cli_buffer->line_buf)
 1283: 				str = e_strdup(cli_buffer->line_buf);
 1284: 			else
 1285: 				cli_SetErr(EPIPE, "Unknown state ...");
 1286: 			return str;
 1287: 		}
 1288: 
 1289: recheck:
 1290: 		for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
 1291: 			if (readLen >= cli_buffer->line_keys[i].key_len && 
 1292: 					!memcmp(cli_buffer->line_keys[i].key_ch, buf, 
 1293: 						cli_buffer->line_keys[i].key_len)) {
 1294: 				readLen -= cli_buffer->line_keys[i].key_len;
 1295: 				if (readLen)
 1296: 					memmove(buf, buf + cli_buffer->line_keys[i].key_len, readLen);
 1297: 				else
 1298: 					memset(buf, 0, cli_buffer->line_keys[i].key_len);
 1299: 
 1300: 				if (cli_buffer->line_keys[i].key_func)
 1301: 					if ((code = cli_buffer->line_keys[i].key_func(i, cli_buffer)))
 1302: 						readLen = 0;
 1303: 
 1304: 				if (readLen)
 1305: 					goto recheck;
 1306: 				else
 1307: 					break;
 1308: 			}
 1309: 
 1310: 		if (code)
 1311: 			break;
 1312: 	}
 1313: 
 1314: 	if (code != RETCODE_ERR && code != RETCODE_EOF && cli_buffer->line_buf)
 1315: 		str = e_strdup(cli_buffer->line_buf);
 1316: 	return str;
 1317: }
 1318: 
 1319: 
 1320: /*
 1321:  * cliNetLoop() - CLI network main loop binded to socket
 1322:  *
 1323:  * @cli_buffer = CLI buffer
 1324:  * @csHistFile = History file name
 1325:  * @sock = client socket
 1326:  * return: RETCODE_ERR error, RETCODE_OK ok
 1327: */
 1328: int
 1329: cliNetLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, int sock)
 1330: {
 1331: 	u_char buf[BUFSIZ];
 1332: 	int pid, stat, pty, r, s, alen, flg, attrlen = 0, ret = 0;
 1333: 	fd_set fds;
 1334: 	struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
 1335: 	struct telnetAttrs *a, Attr[10];
 1336: 
 1337: 	switch ((pid = forkpty(&pty, NULL, NULL, NULL))) {
 1338: 		case -1:
 1339: 			LOGERR;
 1340: 			return -1;
 1341: 		case 0:
 1342: 			if (!cli_buffer) {
 1343: 				cli_SetErr(EINVAL, "Invalid input parameters ...");
 1344: 				return -1;
 1345: 			} else
 1346: 				close(sock);
 1347: 
 1348: 			ret = cliLoop(cli_buffer, csHistFile) < 0 ? 1 : 0;
 1349: 			cliEnd(cli_buffer);
 1350: 
 1351: 			_exit(ret);
 1352: 		default:
 1353: 			cli_telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
 1354: 			cli_telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
 1355: 			cli_telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
 1356: 			cli_telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
 1357: 			cli_telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
 1358: 			if ((ret = cli_telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1)
 1359: 				return -1;
 1360: 			else
 1361: 				flg = 0;
 1362: 
 1363: 			while (42) {
 1364: 				if (waitpid(pid, &stat, WNOHANG))
 1365: 					break;
 1366: 
 1367: 				FD_ZERO(&fds);
 1368: 				FD_SET(sock, &fds);
 1369: 				FD_SET(pty, &fds);
 1370: 				if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
 1371: 					if (!ret)
 1372: 						cli_SetErr(ETIMEDOUT, "Client session timeout ...");
 1373: 
 1374: 					break;
 1375: 				}
 1376: 
 1377: 				r = FD_ISSET(sock, &fds) ? sock : pty;
 1378: 				s = FD_ISSET(sock, &fds) ? pty : sock;
 1379: 
 1380: 				if (FD_ISSET(sock, &fds)) {
 1381: 					memset(buf, 0, BUFSIZ);
 1382: 					if ((ret = cli_telnetRecv(sock, &a, &alen, buf, BUFSIZ)) < 0) {
 1383: 						if (a)
 1384: 							e_free(a);
 1385: 
 1386: 						if (-2 == ret)
 1387: 							continue;
 1388: 						// EOF
 1389: 						if (-3 == ret)
 1390: 							shutdown(sock, SHUT_RD);
 1391: 						break;
 1392: 					}
 1393: 					attrlen = 0;
 1394: 					if (1 == flg && alen) {
 1395: 						cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
 1396: 						cli_telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
 1397: 					}
 1398: 					if (2 == flg && alen) {
 1399: 						cli_telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
 1400: 						cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
 1401: 								LFLOW_OFF, NULL, 0);
 1402: 						cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
 1403: 								LFLOW_RESTART_XON, NULL, 0);
 1404: 						cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
 1405: 					}
 1406: 					if (a)
 1407: 						e_free(a);
 1408: 
 1409: 					if ((ret = write(pty, buf, ret)) == -1) {
 1410: 						LOGERR;
 1411: 						break;
 1412: 					}
 1413: 				}
 1414: 
 1415: 				if (FD_ISSET(pty, &fds)) {
 1416: 					memset(buf, 0, BUFSIZ);
 1417: 					if ((ret = read(pty, buf, BUFSIZ)) == -1) {
 1418: 						LOGERR;
 1419: 						break;
 1420: 					}
 1421: 
 1422: 					if ((ret = cli_telnetSend(sock, Attr, pty == s ? 0 : attrlen, 
 1423: 									buf, ret, 0)) == -1)
 1424: 						break;
 1425: 					else
 1426: 						flg++;
 1427: 				}
 1428: 			}
 1429: 
 1430: 			close(pty);
 1431: 	}
 1432: 
 1433: 	return ret;
 1434: }
 1435: 
 1436: /*
 1437:  * cliLoop() - CLI main loop
 1438:  *
 1439:  * @cli_buffer = CLI buffer
 1440:  * @csHistFile = History file name
 1441:  * return: RETCODE_ERR error, RETCODE_OK ok
 1442: */
 1443: int
 1444: cliLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile)
 1445: {
 1446: 	char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
 1447: 	register int i;
 1448: 	int ret = RETCODE_OK;
 1449: 	struct tagCommand *cmd;
 1450: 
 1451: 	/* --- main body of CLI --- */
 1452: 	cliInitLine(cli_buffer);
 1453: 
 1454: 	if (cli_loadHistory(cli_buffer, csHistFile) == RETCODE_ERR)
 1455: 		return RETCODE_ERR;
 1456: 
 1457: 	do {
 1458: 		line = cliReadLine(cli_buffer);
 1459: 		if (!line) {
 1460: 			printfNL(cli_buffer, 0);
 1461: 			break;
 1462: 		} else
 1463: 			cli_addHistory(cli_buffer, NULL);
 1464: 		// clear whitespaces
 1465: 		for (s = line; isspace((int) *s); s++);
 1466: 		if (*s) {
 1467: 			for (t = s + strlen(s) - 1; t > s && isspace((int) *t); t--);
 1468: 			*++t = 0;
 1469: 		}
 1470: 
 1471: 		if (*s) {
 1472: 			memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
 1473: 			for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && 
 1474: 					(*app = strsep(&s, " \t")); *app ? app++ : app);
 1475: 
 1476: 			// exec_cmd ...
 1477: 			i = 0;
 1478: 			SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) {
 1479: 				if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
 1480: 					break;
 1481: 				else
 1482: 					i++;
 1483: 			}
 1484: 
 1485: 			if (!cmd) {
 1486: 				cli_Printf(cli_buffer, "\nCommand '%s' not found!\n", items[0]);
 1487: 				ret = -1;
 1488: 			} else
 1489: 				if (cmd->cmd_func) {
 1490: 					cli_Printf(cli_buffer, "\n");
 1491: 					ret = cmd->cmd_func(cli_buffer, i, items);
 1492: 				} else {
 1493: 					clrscrEOL(cli_buffer);
 1494: 					printfCR(cli_buffer, 1);
 1495: 				}
 1496: 		}
 1497: 
 1498: 		cli_freeLine(cli_buffer);
 1499: 		cli_resetHistory(cli_buffer);
 1500: 		e_free(line);
 1501: 	} while (ret < 1);
 1502: 
 1503: 	cli_saveHistory(cli_buffer, csHistFile, HISTORY_LINES);
 1504: 	return ret;
 1505: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>