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