Annotation of libaitcli/src/aitcli.c, revision 1.2.2.21
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.2.2.21! misho 6: * $Id: aitcli.c,v 1.2.2.20 2010/12/07 16:20:24 misho Exp $
1.1 misho 7: *
8: *************************************************************************/
9: #include "global.h"
1.2.2.7 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:
20: #pragma GCC visibility pop
21:
22: // cli_GetErrno() Get error code of last operation
1.2.2.2 misho 23: inline int
24: cli_GetErrno()
1.1 misho 25: {
26: return cli_Errno;
27: }
28:
29: // io_GetError() Get error text of last operation
1.2.2.2 misho 30: inline const char *
31: cli_GetError()
1.1 misho 32: {
33: return cli_Error;
34: }
35:
36: // cli_SetErr() Set error to variables for internal use!!!
1.2.2.2 misho 37: inline void
38: cli_SetErr(int eno, char *estr, ...)
1.1 misho 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: }
48:
49: // ------------------------------------------------------------
50:
1.2.2.2 misho 51: static inline void
52: clrscrEOL(linebuffer_t * __restrict buf)
1.1 misho 53: {
1.2.2.2 misho 54: register int i;
1.1 misho 55:
1.2.2.2 misho 56: if (buf) {
57: write(buf->line_out, K_CR, 1);
1.1 misho 58:
1.2.2.2 misho 59: for (i = 0; i < buf->line_len; i++)
60: write(buf->line_out, K_SPACE, 1);
61: }
1.1 misho 62: }
63:
1.2.2.2 misho 64: static inline void
65: printfEOL(linebuffer_t * __restrict buf, int len, int prompt)
1.2 misho 66: {
1.2.2.2 misho 67: if (buf) {
68: write(buf->line_out, K_CR, 1);
1.2 misho 69:
1.2.2.2 misho 70: if (prompt && buf->line_prompt)
71: write(buf->line_out, buf->line_prompt, buf->line_bol);
1.2 misho 72:
1.2.2.2 misho 73: write(buf->line_out, buf->line_buf, len == -1 ? buf->line_eol - buf->line_bol: len);
74: }
1.2 misho 75: }
76:
1.2.2.2 misho 77: static inline void
78: printfCR(linebuffer_t * __restrict buf, int prompt)
1.2 misho 79: {
1.2.2.2 misho 80: if (buf) {
81: write(buf->line_out, K_CR, 1);
82:
83: if (prompt)
84: if (prompt && buf->line_prompt)
85: write(buf->line_out, buf->line_prompt, buf->line_bol);
86: }
1.2 misho 87: }
88:
1.2.2.2 misho 89: static inline void
1.2.2.4 misho 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:
1.2.2.2 misho 101: // ------------------------------------------------------------
102:
1.2.2.3 misho 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) {
1.2.2.12 misho 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);
1.2.2.3 misho 129: printfEOL(buf, -1, 1);
130: }
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: {
1.2.2.12 misho 147: /*
1.2.2.3 misho 148: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
149: return RETCODE_ERR;
1.2.2.12 misho 150: */
1.2.2.3 misho 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);
270: }
271:
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;
313: }
314:
315: static int
316: bufLEFT(int idx, void * __restrict buffer)
317: {
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: }
328:
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:
1.2.2.8 misho 365: static int
366: bufComp(int idx, void * __restrict buffer)
367: {
368: linebuffer_t *buf = buffer;
1.2.2.12 misho 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;
1.2.2.8 misho 373:
374: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
375: return RETCODE_ERR;
376:
1.2.2.9 misho 377: str = strdup(buf->line_buf);
378: if (!str)
379: return RETCODE_ERR;
380: else {
381: s = str;
382: io_TrimStr((u_char*) s);
383: }
384:
1.2.2.12 misho 385: i = j = 0;
386: c = NULL;
387: memset(szLine, 0, STRSIZ);
1.2.2.9 misho 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:
1.2.2.12 misho 393: if (i) {
1.2.2.15 misho 394: SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
1.2.2.12 misho 395: if (cmd->cmd_level == buf->line_level &&
396: !strncmp(cmd->cmd_name, items[0], strlen(items[0]))) {
1.2.2.15 misho 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: }
1.2.2.12 misho 403: }
1.2.2.15 misho 404: }
1.2.2.12 misho 405:
1.2.2.13 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);
1.2.2.12 misho 410: }
411: } else {
412: /* we have valid char but i == 0, this case is illegal */
413: ret = RETCODE_ERR;
414: goto endcomp;
415: }
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)
1.2.2.15 misho 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: }
1.2.2.12 misho 426: }
427: }
428:
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);
1.2.2.13 misho 434: printfEOL(buf, buf->line_len - 1, 1);
435: printfEOL(buf, -1, 1);
1.2.2.12 misho 436: }
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;
449:
450: printfEOL(buf, -1, 1);
1.2.2.9 misho 451: }
452:
1.2.2.12 misho 453: endcomp:
1.2.2.9 misho 454: free(str);
1.2.2.12 misho 455: return ret;
1.2.2.8 misho 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);
1.2.2.13 misho 467:
468: printfEOL(buf, buf->line_len - 1, 1);
469: printfEOL(buf, -1, 1);
1.2.2.8 misho 470: return RETCODE_OK;
471: }
472:
1.2.2.3 misho 473: // ---------------------------------------------------------------
474:
475: /*
1.2.2.4 misho 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: /*
1.2.2.14 misho 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: {
1.2.2.21! misho 510: if (buffer) {
1.2.2.14 misho 511: bufHelp(0, buffer);
1.2.2.21! misho 512: clrscrEOL(buffer);
! 513: } else
1.2.2.14 misho 514: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
515: }
516:
517:
518: /*
1.2.2.3 misho 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;
532: }
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;
542: }
543:
544:
545: /*
1.2.2.6 misho 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,
1.2.2.13 misho 557: const char *csInfo, const char *csHelp)
1.2.2.6 misho 558: {
559: struct tagCommand *cmd;
560:
1.2.2.14 misho 561: if (!buffer || !csCmd) {
1.2.2.6 misho 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;
582: }
583:
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)
593: {
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;
611: }
612:
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,
1.2.2.13 misho 625: const char *csInfo, const char *csHelp)
1.2.2.6 misho 626: {
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:
1.2.2.13 misho 639: if (funcCmd)
1.2.2.6 misho 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: }
648:
649: return ret;
650: }
651:
652:
653: /*
1.2.2.3 misho 654: * cli_addHistory() Add line to history
655: * @buffer = CLI buffer
1.2.2.4 misho 656: * @str = Add custom text or if NULL use readed line from CLI buffer
1.2.2.3 misho 657: * return: RETCODE_ERR error, RETCODE_OK ok
658: */
659: int
660: cli_addHistory(linebuffer_t * __restrict buffer, const char * __restrict str)
661: {
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: }
692:
693: TAILQ_INSERT_HEAD(&buffer->line_history, h, hist_next);
694: return h->hist_len;
695: }
696:
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) {
724: LOGERR;
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: }
736:
737: fclose(f);
738: umask(mode);
739:
740: return RETCODE_OK;
741: }
742:
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");
1.2.2.4 misho 766: if (!f)
767: return RETCODE_OK;
1.2.2.3 misho 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: }
790:
791: /*
792: * cli_resetHistory() Reset history search in CLI session
793: * @buffer = CLI buffer
794: * return: none
795: */
796: inline void
797: cli_resetHistory(linebuffer_t * __restrict buffer)
798: {
799: buffer->line_h = NULL;
800: }
801:
802:
803: /*
804: * cli_freeLine() Clear entire line
805: * @buffer = CLI buffer
806: * return: RETCODE_ERR error, RETCODE_OK ok
807: */
808: inline int
809: cli_freeLine(linebuffer_t * __restrict buffer)
810: {
811: int code = RETCODE_ERR;
812:
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;
822:
823: code = RETCODE_OK;
824: } else
825: LOGERR;
826: } else
827: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
828:
829: return code;
830: }
831:
832: /*
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
837: */
838: inline void
839: cli_setPrompt(linebuffer_t * __restrict buffer, const char *prompt)
840: {
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 ...");
859: }
860:
861:
862: /*
863: * cliEnd() Clear data, Free resources and close CLI session
864: * @buffer = CLI buffer
865: * return: RETCODE_ERR error, RETCODE_OK ok
866: */
867: void
868: cliEnd(linebuffer_t * __restrict buffer)
869: {
870: struct tagHistory *h;
1.2.2.4 misho 871: struct tagCommand *c;
1.2.2.3 misho 872:
873: if (buffer) {
1.2.2.4 misho 874: while ((c = SLIST_FIRST(&buffer->line_cmds))) {
875: SLIST_REMOVE_HEAD(&buffer->line_cmds, cmd_next);
876: free(c);
877: }
1.2.2.3 misho 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);
885:
886: if (buffer->line_keys)
887: free(buffer->line_keys);
888: if (buffer->line_buf)
889: free(buffer->line_buf);
890:
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 */
1.2.2.18 misho 912: buffer = malloc(sizeof(linebuffer_t));
1.2.2.3 misho 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);
1.2.2.4 misho 923: SLIST_INIT(&buffer->line_cmds);
1.2.2.3 misho 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:
1.2.2.7 misho 957: /* add helper functions */
1.2.2.13 misho 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");
1.2.2.15 misho 960: cli_addCommand(buffer, "-------", 0, NULL, "-------------------------", NULL);
1.2.2.7 misho 961:
1.2.2.3 misho 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;
1.2.2.8 misho 980: if (i == *K_TAB)
981: keys[i].key_func = bufComp;
1.2.2.3 misho 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;
1.2.2.8 misho 986: if (i == '?')
987: keys[i].key_func = bufHelp;
1.2.2.3 misho 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:
1.2.2.18 misho 1150: buffer->line_keys = keys;
1151: return buffer;
1152: }
1153:
1154: /*
1155: * cliInitLine() Init CLI input line terminal
1156: * @buffer = CLI buffer
1157: * return: none
1158: */
1159: int
1160: cliInitLine(linebuffer_t * __restrict buffer)
1161: {
1162: struct termios t;
1163:
1164: memset(&t, 0, sizeof t);
1.2.2.3 misho 1165: tcgetattr(buffer->line_in, &t);
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.2.2.18 misho 1170: return tcsetattr(buffer->line_in, TCSANOW, &t);
1.2.2.3 misho 1171: }
1172:
1.2 misho 1173: /*
1.2.2.4 misho 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!
1.2 misho 1177: */
1.2.2.4 misho 1178: char *
1179: cliReadLine(linebuffer_t * __restrict buffer)
1.2 misho 1180: {
1.2.2.4 misho 1181: int code, readLen;
1182: register int i;
1183: struct pollfd fds;
1184: char buf[BUFSIZ], *str = NULL;
1.2 misho 1185:
1.2.2.4 misho 1186: if (!buffer) {
1187: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1188: return NULL;
1.2 misho 1189: }
1190:
1.2.2.4 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: }
1.2 misho 1201:
1.2.2.4 misho 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: }
1.2 misho 1215:
1.2.2.4 misho 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: }
1.2 misho 1236:
1.2.2.4 misho 1237: if (code)
1238: break;
1239: }
1240:
1.2.2.5 misho 1241: if (code != RETCODE_ERR && code != RETCODE_EOF && buffer->line_buf)
1.2.2.4 misho 1242: str = strdup(buffer->line_buf);
1243: return str;
1.2 misho 1244: }
1.2.2.4 misho 1245:
1246:
1.2 misho 1247: /*
1.2.2.4 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.2.2.4 misho 1252: * return: RETCODE_ERR error, RETCODE_OK ok
1.2 misho 1253: */
1.2.2.1 misho 1254: int
1.2.2.17 misho 1255: cliNetLoop(linebuffer_t * __restrict buffer, const char *csHistFile, int sock)
1.2 misho 1256: {
1.2.2.4 misho 1257: u_char buf[BUFSIZ];
1.2.2.20 misho 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.2.2.20 misho 1263: switch ((pid = forkpty(&pty, NULL, NULL, NULL))) {
1.2 misho 1264: case -1:
1265: LOGERR;
1266: return -1;
1267: case 0:
1.2.2.18 misho 1268: if (!buffer) {
1.2.2.8 misho 1269: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1.2.2.18 misho 1270: return -1;
1271: } else
1272: close(sock);
1.2.2.4 misho 1273:
1.2.2.18 misho 1274: ret = cliLoop(buffer, csHistFile) < 0 ? 1 : 0;
1275: cliEnd(buffer);
1.2.2.4 misho 1276:
1.2.2.18 misho 1277: exit(ret);
1.2 misho 1278: default:
1279: telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
1280: telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
1281: telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
1282: telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
1283: telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
1284: if ((ret = telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1) {
1285: cli_Errno = telnet_GetErrno();
1286: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1287: return -1;
1288: } else
1289: flg = 0;
1290:
1291: while (42) {
1.2.2.20 misho 1292: if (waitpid(pid, &stat, WNOHANG))
1293: break;
1294:
1.2 misho 1295: FD_ZERO(&fds);
1296: FD_SET(sock, &fds);
1297: FD_SET(pty, &fds);
1298: if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
1299: if (!ret)
1300: cli_SetErr(ETIMEDOUT, "Client session timeout ...");
1301:
1302: break;
1303: }
1304:
1305: r = FD_ISSET(sock, &fds) ? sock : pty;
1306: s = FD_ISSET(sock, &fds) ? pty : sock;
1307:
1.2.2.17 misho 1308: if (FD_ISSET(sock, &fds)) {
1309: memset(buf, 0, BUFSIZ);
1310: if ((ret = telnetRecv(sock, &a, &alen, buf, BUFSIZ)) < 0) {
1311: if (a)
1312: free(a);
1313:
1314: if (-2 == ret)
1315: continue;
1316: // EOF
1317: if (-3 == ret)
1318: shutdown(sock, SHUT_RD);
1319: else {
1320: cli_Errno = telnet_GetErrno();
1321: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1322: }
1323: break;
1324: }
1325: attrlen = 0;
1326: if (1 == flg && alen) {
1327: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
1328: telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
1329: }
1330: if (2 == flg && alen) {
1331: telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
1332: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1333: LFLOW_OFF, NULL, 0);
1334: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1335: LFLOW_RESTART_XON, NULL, 0);
1336: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
1337: }
1.2 misho 1338: if (a)
1339: free(a);
1340:
1.2.2.17 misho 1341: if ((ret = write(pty, buf, ret)) == -1) {
1342: LOGERR;
1343: break;
1.2 misho 1344: }
1345: }
1346:
1.2.2.17 misho 1347: if (FD_ISSET(pty, &fds)) {
1348: memset(buf, 0, BUFSIZ);
1349: if ((ret = read(pty, buf, BUFSIZ)) == -1) {
1350: LOGERR;
1351: break;
1352: }
1353:
1354: if ((ret = telnetSend(sock, Attr, pty == s ? 0 : attrlen, buf, ret, 0)) == -1) {
1355: cli_Errno = telnet_GetErrno();
1356: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1357: break;
1358: } else
1359: flg++;
1360: }
1.2 misho 1361: }
1362:
1363: close(pty);
1364: }
1365:
1366: return ret;
1367: }
1368:
1369: /*
1.2.2.4 misho 1370: * cliLoop() CLI main loop
1371: * @buffer = CLI buffer
1372: * @csHistFile = History file name
1373: * return: RETCODE_ERR error, RETCODE_OK ok
1.1 misho 1374: */
1.2.2.4 misho 1375: int
1376: cliLoop(linebuffer_t * __restrict buffer, const char *csHistFile)
1.1 misho 1377: {
1378: char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
1379: register int i;
1.2.2.4 misho 1380: int ret = RETCODE_OK;
1381: struct tagCommand *cmd;
1.1 misho 1382:
1383: /* --- main body of CLI --- */
1.2.2.19 misho 1384: cliInitLine(buffer);
1.2.2.4 misho 1385:
1386: if (cli_loadHistory(buffer, csHistFile) == RETCODE_ERR)
1387: return RETCODE_ERR;
1.1 misho 1388:
1389: do {
1.2.2.4 misho 1390: line = cliReadLine(buffer);
1.2.2.5 misho 1391: if (!line) {
1392: printfNL(buffer, 0);
1.1 misho 1393: break;
1.2.2.5 misho 1394: } else
1.2.2.4 misho 1395: cli_addHistory(buffer, NULL);
1.1 misho 1396: // clear whitespaces
1397: for (s = line; isspace(*s); s++);
1398: if (*s) {
1399: for (t = s + strlen(s) - 1; t > s && isspace(*t); t--);
1400: *++t = 0;
1401: }
1402:
1403: if (*s) {
1404: memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
1405: for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && (*app = strsep(&s, " \t"));
1406: *app ? app++ : app);
1407:
1408: // exec_cmd ...
1.2.2.4 misho 1409: i = 0;
1410: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next) {
1411: if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
1.1 misho 1412: break;
1.2.2.4 misho 1413: else
1414: i++;
1415: }
1.2.2.5 misho 1416:
1.1 misho 1417: if (!cmd) {
1.2.2.5 misho 1418: cli_Printf(buffer, "\nCommand '%s' not found!\n", items[0]);
1.1 misho 1419: ret = -1;
1420: } else
1.2.2.20 misho 1421: if (cmd->cmd_func) {
1422: cli_Printf(buffer, "\n");
1.2.2.15 misho 1423: ret = cmd->cmd_func(buffer, i, items);
1.2.2.20 misho 1424: } else {
1.2.2.15 misho 1425: clrscrEOL(buffer);
1426: printfCR(buffer, 1);
1427: }
1.1 misho 1428: }
1429:
1.2.2.4 misho 1430: cli_freeLine(buffer);
1431: cli_resetHistory(buffer);
1.1 misho 1432: free(line);
1433: } while (ret < 1);
1434:
1.2.2.4 misho 1435: cli_saveHistory(buffer, csHistFile, HISTORY_LINES);
1.1 misho 1436: return ret;
1437: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>